Skip to content

How to use quartobot in a Quarto website

quartobot’s pre-render hook works on every Quarto project type, but the documentation so far has been manuscript-shaped. Websites change three things worth covering on their own page: one references.json shared across all pages, format.html.bibliography: resolves relative to each page, and the _freeze/ cache interacts with cite-key changes in unobvious ways. The rest is the same.

Quarto’s own scaffolder writes the website layout:

Terminal window
quarto create project website my-site
cd my-site

Layer the citation pipeline on top:

Terminal window
quartobot init

Same UX as the manuscript path. Because quarto create project already wrote a _quarto.yml, init will not touch it; it prints a YAML snippet to paste in yourself. Merge the snippet under the existing project: block. The resulting _quarto.yml looks like:

project:
type: website
pre-render: quartobot resolve --from-scan . --output references.json --id-mode citation-key
website:
title: "My site"
navbar:
- href: index.qmd
text: Home
- href: about.qmd
text: About
bibliography:
- references.bib
- references.json

init also seeds an empty references.bib for hand-curated entries (anything without a persistent identifier — a personal communication, a webpage with no DOI) and adds _freeze/, .quarto/, *_files/, and references.json to .gitignore.

That’s the wiring. Every quarto render and quarto preview now runs quartobot resolve first; pandoc-citeproc reads the resulting references.json alongside references.bib.

A website is multiple pages. Some cite, some don’t. The pre-render hook does not care: quartobot scan walks the whole project, quartobot resolve resolves every cite key it finds across every page into one shared references.json at the project root. The bibliography is one file, not one per page.

Each page’s rendered HTML carries only the references actually cited on that page. That’s pandoc-citeproc’s default — it filters the bibliography down to the keys cited in the document. A page that cites nothing renders with no reference list at all. A page that cites three keys renders with three entries, even though references.json holds dozens.

If you need an entry to appear in a page’s bibliography list without an inline citation — a “further reading” section, say — pandoc’s nocite: field in the page frontmatter forces it in:

---
title: "About"
nocite: |
@doi:10.1371/journal.pcbi.1007128
---

That is pandoc behavior, not quartobot’s, and it’s documented in the pandoc manual under “Including uncited items in the bibliography.”

Quarto’s _freeze/ directory caches rendered output per page so that quarto render skips pages whose source hasn’t changed. The interaction with the pre-render hook has one gotcha worth knowing.

When you change a cite key inside a .qmd page, _freeze/ invalidates that page (its source hash changed) but does not invalidate references.json. The pre-render hook runs on every render anyway, so the new key gets resolved and the bibliography updates correctly. This works the way you’d want.

The case that bites: you change only _quarto.yml’s bibliography: list — add a second .bib file, say. No .qmd source hash changes, so _freeze/ thinks nothing needs re-rendering, and the new bibliography entries never reach the rendered HTML. Run quarto render --no-freeze once to bust the cache. After that, normal quarto render picks up the new bibliography on every page.

A two-page site sharing one bibliography.

my-site/
├── _quarto.yml
├── index.qmd
├── methods.qmd
├── references.bib
└── references.json # generated by quartobot resolve

_quarto.yml:

project:
type: website
pre-render: quartobot resolve --from-scan . --output references.json --id-mode citation-key
website:
title: "Lab notebook"
navbar:
- href: index.qmd
text: Home
- href: methods.qmd
text: Methods
bibliography:
- references.bib
- references.json

index.qmd:

---
title: "Home"
---
The manubot pattern [@doi:10.1371/journal.pcbi.1007128] runs scholarly
writing as software.

methods.qmd:

---
title: "Methods"
---
GTEx Consortium pilot data [@pmid:23685459] is the worked example.

Render:

Terminal window
quarto render

The pre-render hook scans both pages, resolves both keys (one via Crossref, one via PubMed), and writes references.json with both entries. Pandoc-citeproc reads references.bib + references.json per page and emits one reference list per page: index.html carries the manubot citation, methods.html carries the GTEx citation, neither carries the other’s. A third page citing both keys would carry both entries; a fourth citing neither would carry no reference list at all. That’s pandoc-citeproc’s default, not quartobot’s.