# A BibTeX editor for libraries that outgrew the GUI thread

**URL:** <https://discourse.jabref.org/t/a-bibtex-editor-for-libraries-that-outgrew-the-gui-thread/9167>\
**Category:** Speaker's corner\
**Created:** [October 25, 2026, 9:31am UTC](https://discourse.jabref.org/t/a-bibtex-editor-for-libraries-that-outgrew-the-gui-thread/9167 "2026-10-25T09:31:12Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![emfox](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.jabref.org/emfox/32/2618_2.png) [@emfox](https://discourse.jabref.org/u/emfox)\
**Post date:** [October 25, 2026, 9:31am UTC](https://discourse.jabref.org/t/a-bibtex-editor-for-libraries-that-outgrew-the-gui-thread/9167/1 "2026-10-25T09:31:13Z")

</div>

I built this to answer one question that no manager I tried would answer: when a large `.bib` takes ten seconds to appear, where did the ten seconds go — the parse, the index, or the table?

citerack answers it by reporting each step. The file is parsed on a worker thread, the index is built before the first row is drawn, and `--open-time` prints how long each took. That is the whole design, and everything below is a consequence of taking it seriously: an index that is built once instead of per keystroke, a save that writes back only the bytes that changed, a window that stays responsive because nothing blocking runs on the thread that draws it.

It is called citerack, it is licensed under MIT, and it is at [GitHub - emfox/citerack: A BibTeX editor for large libraries: it opens a hundred thousand entries in a few seconds and writes back only the bytes you changed. · GitHub](https://github.com/emfox/citerack)

![The window](https://raw.githubusercontent.com/emfox/citerack/main/docs/images/window.png)

**What it does**

- Opens 100 000 entries in about 2.6 s on a single shared core, at a flat 25–26 µs per entry as the library grows. `docs/Performance.md` has the figures, the machine and the command that re-derives each one — compare per-entry cost, not total seconds.

- Saves byte for byte. Editing one title in the 45 974-entry library mentioned below changed 44 of 4 936 765 bytes — the rest of the file, including comments and fields it does not model, is untouched.

- Searches every field at once, ignoring case and accents, in about 1 ms on 100 000 entries. Greek, Cyrillic, Arabic and CJK split on their own word boundaries.

- Filters by author, journal, year and type, with a count that is what the filter would actually leave.

- Finds duplicates by DOI, or by title and year with case, accents, braces and punctuation folded away.

- Generates citation keys from a pattern, previewed in a column before anything is written.

- Marks the fields an entry’s type requires but the file lacks, and adds them when you write in the empty box.

- Writes one field across a picked range of entries as a single undo step.

- Takes a DOI or an arXiv id, asks Crossref or arXiv, and files what comes back under a key the library does not hold yet.

- Opens the paper from an entry’s `file` field, reading the paths JabRef, Zotero and Mendeley write, and says `missing` beside a path that is not there.

- Follows the desktop’s light or dark preference, unless told otherwise.

- Works without a mouse.

**Where it might not suit you**

It edits one library at a time and keeps no database — the `.bib` file is the only copy, which is the point. Attachments are opened, not managed. The interface is English. Risks it would rather not take, it does not take: a file it does not fully understand is read conservatively rather than rewritten.

And the obvious one: it has been built against generated libraries and two donated fixtures, not against years of your habits. If your library is the kind that has accumulated a decade of exceptions, expect to be the one who finds the exceptions.

**Why I am posting here**

Not to argue that anyone should switch. I am posting because this forum is where people who care about BibTeX as a format, rather than as an export option, actually are, and two things would be worth more than stars:

1. If you have a library that is slow to open in _anything_, I would like to measure it. `citerack --open-time your.bib` prints the parse, the index and the memory, and a number with a size attached is something I can act on.

2. If it reads a file wrong, that is a bug I want. The parser is deliberately conservative about what it does not understand, and I would rather hear about the case it gets wrong than find out later.

The figures above come from `scripts/genlib.py` and from two libraries a user attached to a bug report about scrolling elsewhere — 45 974 and 134 352 entries, committed as fixtures. Those two are the inputs I did not generate myself, and they are the ones that disagreed with my assumptions. A third would be welcome.

The binary is a Linux and a Windows build per tagged release, with checksums. There is no installer and no telemetry.

One last thing. I am a programmer, but not a Rust one, and English is not my first language — this text included. What is in the repository got there with translation tools, AI assistance, and a lot of reading of what the compiler said. If a sentence here reads oddly, or a comment in the code does, that is why, and a correction is welcome rather than embarrassing.

---

<div class="post-metadata">

**Author:** ![koppor](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.jabref.org/koppor/32/5_2.png) [@koppor](https://discourse.jabref.org/u/koppor)\
**Post date:** [October 25, 2026, 9:34am UTC](https://discourse.jabref.org/t/a-bibtex-editor-for-libraries-that-outgrew-the-gui-thread/9167/2 "2026-10-25T09:34:59Z")

</div>

Opening a large file without offering much featuers is easy.

This is possible with JabRef 1.0. Get it from [https://sourceforge.net/projects/jabref/files/v1.0%20to%20v2.11.1/1.0/](https://sourceforge.net/projects/jabref/files/v1.0%20to%20v2.11.1/1.0/)

The hard part are the UX features and follow all user requests.

You are very welcome to

- implement everything JabRef has
- Fix all issues from [Issues · JabRef/jabref · GitHub](https://github.com/JabRef/jabref/issues)
- Fix all issues from [Issues · JabRef/jabref-koppor · GitHub](https://github.com/JabRef/jabref-koppor/issues)
- Implement all wishes from the forum.

Then we can finally use software and not manage issues. Thank you in advance.

---

<div class="post-metadata">

**Author:** ![koppor](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.jabref.org/koppor/32/5_2.png) [@koppor](https://discourse.jabref.org/u/koppor)\
**Post date:** [October 25, 2026, 9:36am UTC](https://discourse.jabref.org/t/a-bibtex-editor-for-libraries-that-outgrew-the-gui-thread/9167/3 "2026-10-25T09:36:18Z")

</div>

As first step, I urge to collect all features and requirements as markdown files in docs/ so that your AI(s) can work on it.

---

<div class="post-metadata">

**Author:** ![koppor](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.jabref.org/koppor/32/5_2.png) [@koppor](https://discourse.jabref.org/u/koppor)\
**Post date:** [October 25, 2026, 9:37am UTC](https://discourse.jabref.org/t/a-bibtex-editor-for-libraries-that-outgrew-the-gui-thread/9167/4 "2026-10-25T09:37:14Z")

</div>

You can join forces with [Proposal: Creation of a Software Requirements Specification (SRS) Document for JabRef](https://discourse.jabref.org/t/proposal-creation-of-a-software-requirements-specification-srs-document-for-jabref/9143).

---

<div class="post-metadata">

**Author:** ![AlaynaKerluke](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.jabref.org/alaynakerluke/32/2624_2.png) [@AlaynaKerluke](https://discourse.jabref.org/u/AlaynaKerluke)\
**Post date:** [October 26, 2026, 6:55pm UTC](https://discourse.jabref.org/t/a-bibtex-editor-for-libraries-that-outgrew-the-gui-thread/9167/5 "2026-10-26T18:55:02Z")

</div>

`--open-time` currently collapses three different costs into one number: reading and parsing, building the index, and the time before the first row can be drawn. The headless command only covers the first two. That is fine for a single tool, but it makes a comparison with JabRef hard to audit, because a reader cannot tell whether a gap comes from parsing, from indexing, or from the GUI, and JabRef’s startup also includes JVM warmup that a Rust binary does not have.

A useful addition would be an explicit phase split: a `--open-phases` mode that prints parse-only and index-build timings separately, plus a first-row-paint measurement taken from the GUI, each labelled with the library actually used, with entry count and file size in MiB (for example the 100 000-entry, roughly 140 MiB set that `scripts/genlib.py` generates). Alongside that, state cold versus warm: cold as the first run after dropping the page cache, warm as an immediate repeat, with at least five repetitions and median plus p95 rather than a single wall time. Pinning the process to one core and recording the CPU model and filesystem also matters, since a per-entry cost of 25–26 µs is sensitive to both. On the JabRef side, the equivalent figures need JVM warmup separated from steady state.

With the phase split, the cold and warm labels, and the dataset size stated per figure, someone else can reproduce the comparison and see which phase actually accounts for the ten seconds.

---

<div class="post-metadata">

**Author:** ![ThiloteE](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.jabref.org/thilotee/32/1008_2.png) [@ThiloteE](https://discourse.jabref.org/u/ThiloteE)\
**Post date:** [October 27, 2026, 9:25pm UTC](https://discourse.jabref.org/t/a-bibtex-editor-for-libraries-that-outgrew-the-gui-thread/9167/6 "2026-10-27T21:25:32Z")

</div>

Your comparison is meaningless, if you don’t add the commit hash and maybe the version number of JabRef and Citerack that was used for the comparison. JabRef changes everyday.
