Convert BibTeX to CSL-JSON
CSL-JSON is the bibliography format that Pandoc, citeproc-js, and
reference managers like Zotero use internally. If you write in Markdown and render
with Pandoc, a .json bibliography is often cleaner to work with than .bib. This
tool reads standard BibTeX entries and emits a CSL-JSON array you can drop into your
Pandoc workflow.
How it works
The parser scans for @type{key, ...} blocks, tracking brace depth so nested braces
inside a field value do not end the entry early. Each field = {value} or
field = "value" pair is captured, and surrounding braces and quotes are stripped.
Fields are then mapped onto CSL variables: title→title, journal/booktitle→container-title,
volume→volume, number→issue, pages→page (with -- normalised to -), doi→DOI,
publisher→publisher. The author and editor fields are split on and into CSL
name objects with family/given. The year becomes an issued object whose
date-parts is [[year]]. The BibTeX entry type chooses the CSL type
(@article→article-journal, @inproceedings→paper-conference, and so on).
When to use this converter
You will need CSL-JSON specifically when:
- Passing a bibliography to Pandoc via
--bibliography refs.json— Pandoc’s citeproc natively reads CSL-JSON without any extra filter. - Importing into Zotero using the Better BibTeX or CSL JSON import option, which preserves richer metadata than the BibTeX import path.
- Using citation tools in Obsidian, Quarto, or R Markdown that call citeproc under the hood.
- Building a citations API where JSON is far easier to parse downstream than raw
.bibtext.
Worked example
An @article entry like this:
@article{Smith2021,
author = {Smith, Alice and Jones, Bob},
title = {A study of things},
journal = {Journal of Things},
year = {2021},
volume = {12},
pages = {100--110},
doi = {10.1234/jot.2021}
}
becomes a CSL-JSON item:
{
"id": "Smith2021",
"type": "article-journal",
"title": "A study of things",
"author": [
{"family": "Smith", "given": "Alice"},
{"family": "Jones", "given": "Bob"}
],
"container-title": "Journal of Things",
"volume": "12",
"page": "100-110",
"DOI": "10.1234/jot.2021",
"issued": {"date-parts": [[2021]]}
}
Note that the page range -- is normalised to a single -, and the year becomes the issued date object that Pandoc sorts on.
Notes and edge cases
The output id of each CSL item is the BibTeX cite key, so in-text citations like
[@Smith2021] keep working after conversion. Page ranges written with a single
hyphen, an en-dash, or -- are all normalised to a single hyphen, which is what
CSL expects.
Multiple BibTeX entries in one paste are all converted: the output is a single JSON array containing one object per entry, which is the format --bibliography expects. Fields not listed in the mapping are silently dropped rather than forwarded as unknown keys, keeping the JSON clean for citeproc.