16 Quarto
There is a category of document that Pandoc and LaTeX do not handle well: the document where the content is produced by computation. An analysis in which the charts, tables, and summary statistics are generated by code — Python, R, Julia — and where the narrative and the code are the same artifact, not two separate files that must be kept in sync. When the data changes, or the analysis is revised, the document must be regenerated with the new results embedded correctly. This is the reproducible research problem, and it is the problem Quarto was built to solve.
Quarto is Posit’s open-source scientific and technical publishing system, released in 2022 as the successor to R Markdown. It extends Pandoc Markdown with executable code blocks in Python, R, Julia, and Observable JavaScript, and it wraps the whole system in a polished publishing framework with support for articles, books, websites, presentations, and interactive dashboards. If Pandoc is the universal converter and LaTeX is the typographic engine, Quarto is the scientific publishing system that combines both, adds code execution, and makes the result approachable.
This chapter covers Quarto from the CLI author’s perspective: its document format, its execution model, its project types, its customisation system, and the patterns that make reproducible documents practical.
16.1 Installation and setup
Quarto is a standalone tool that installs separately from R or Python. The installation includes Pandoc (a specific version bundled with Quarto) and does not depend on a system Pandoc installation.
# Download and install on Linux
curl -LO https://quarto.org/download/latest/quarto-linux-amd64.deb
sudo dpkg -i quarto-linux-amd64.deb
# Verify installation
quarto checkquarto check is essential after installation — it reports which execution engines are available and whether their dependencies are satisfied:
[✓] Checking versions of quarto binary dependencies...
Pandoc version 3.1.9: OK
[✓] Checking versions of quarto dependencies......OK
[✓] Checking Quarto installation......OK
[✓] Checking Python 3 installation....Python 3.12.3
Jupyter: 5.7.2
Kernels: python3, ir
[✓] Checking R installation...........R 4.3.2
knitr: 1.45
[✓] Checking tools....................OK
The output reveals which engines are available. For Python execution, Quarto uses Jupyter; for R, it uses knitr. Both can coexist in the same installation and even in the same document.
16.2 The QMD format
Quarto documents use the .qmd file extension (Quarto Markdown). They are Pandoc Markdown with two additions: a richer YAML front matter system that drives format selection and rendering options, and executable code blocks.
The YAML front matter controls every aspect of output: which formats to produce, what settings to apply to each, document metadata, bibliography, and execution behaviour. Unlike Pandoc’s single output path per invocation, a QMD file can declare multiple output formats and Quarto will render all of them:
---
title: "Analysis of Typeface Legibility"
author:
- name: "A. N. Author"
affiliation: "University of Example"
email: author@example.edu
date: "2024-03-15"
format:
html:
toc: true
toc-depth: 3
number-sections: true
code-fold: true
pdf:
documentclass: article
geometry: margin=25mm
mainfont: "EB Garamond"
pdf-engine: xelatex
bibliography: references.bib
---Running quarto render document.qmd renders all declared formats. Running quarto render document.qmd --to html renders only HTML. The YAML metadata is automatically translated to the appropriate Pandoc options and template variables for each format.
16.3 Executable code blocks
A code block becomes executable by giving its language in curly braces: ```{python} instead of ```python. When Quarto encounters an executable block, it passes the code to the appropriate execution engine, captures the output, and embeds both the code and output in the rendered document.
#| label: fig-typeface-comparison
#| fig-cap: "Reading speed by typeface at three sizes"
#| echo: false
#| warning: false
import matplotlib.pyplot as plt
import numpy as np
typefaces = ["Garamond", "Palatino", "Times New Roman"]
sizes_pt = [9, 11, 14]
# Hypothetical reading speeds (wpm)
speeds = np.array([
[220, 255, 268],
[225, 258, 271],
[218, 250, 265],
])
fig, ax = plt.subplots(figsize=(7, 4))
x = np.arange(len(typefaces))
width = 0.25
for i, size in enumerate(sizes_pt):
ax.bar(x + i*width, speeds[:, i], width, label=f"{size}pt")
ax.set_xticks(x + width)
ax.set_xticklabels(typefaces)
ax.set_ylabel("Words per minute")
ax.legend(title="Size")
plt.tight_layout()
plt.show()The lines beginning with #| are chunk options — YAML-formatted settings for the specific block. The most important chunk options:
Visibility: - echo: true/false — show or hide the source code - output: true/false — show or hide the output - include: true/false — include or exclude the entire block (code and output) - warning: false — suppress warning messages - error: false — suppress errors (document fails if an error occurs)
Figures: - label: fig-name — assigns a cross-reference label (must begin fig- for figures) - fig-cap: "Caption text" — figure caption - fig-width: 6 — figure width in inches - fig-height: 4 — figure height in inches - fig-format: svg — output format (png, svg, pdf) - fig-dpi: 300 — resolution for raster formats
Tables: - label: tbl-name — table cross-reference label (must begin tbl-) - tbl-cap: "Caption" — table caption
Execution: - eval: false — show code but do not execute it - cache: true — cache results to avoid re-running expensive computations - dependson: "other-chunk" — invalidate cache if another chunk changes
Cross-references to figures and tables use the same @label syntax as citations:
As shown in @fig-typeface-comparison, reading speed increases with
font size across all three typefaces (see also @tbl-summary-stats).This produces “As shown in Figure 1” in the output, with a clickable hyperlink in HTML and a correct reference in PDF. The system handles numbering automatically, even across output formats where figures are numbered differently.
16.4 Inline code and computed values
Beyond code blocks, individual values computed in code can be interpolated into prose. In Python documents:
The dataset contains `{python} len(df)` observations collected
between `{python} df.date.min().strftime('%B %Y')` and
`{python} df.date.max().strftime('%B %Y')`.In R documents, the syntax uses backtick-r:
The mean reading speed was `r round(mean(speeds), 1)` words per minute
(SD = `r round(sd(speeds), 1)`).This pattern — embedding computed values directly in prose — is the core of the reproducible document workflow. When the data changes and the document is re-rendered, every computed value updates automatically. The prose never drifts from the analysis.
16.5 Project types
A standalone .qmd file is suitable for single documents. For larger work, Quarto projects provide structure: a _quarto.yml configuration file defines the project type, shared settings, and the collection of documents that constitute the project.
16.5.1 Books
A Quarto book renders a collection of .qmd files as a multi-format book with automatic chapter numbering, cross-references that work across chapters, and a navigation interface in the HTML output.
The _quarto.yml for a book:
project:
type: book
output-dir: _book
book:
title: "The CLI Typographer"
author: "A. N. Author"
date: "2024"
cover-image: assets/cover.jpg
chapters:
- index.qmd
- part: "Foundations"
chapters:
- chapters/01-history.qmd
- chapters/02-fundamentals.qmd
- part: "The Workflow"
chapters:
- chapters/03-markdown.qmd
- chapters/04-pandoc.qmd
- references.qmd
bibliography: references.bib
format:
html:
theme: [cosmo, custom.scss]
number-sections: true
toc-depth: 3
pdf:
documentclass: scrbook
classoption: [12pt, twoside]
geometry: "margin=25mm, bindingoffset=10mm"
mainfont: "EB Garamond"
pdf-engine: xelatex
epub:
cover-image: assets/cover.jpgThe part: key introduces a named part containing sub-chapters — an optional layer of hierarchy above chapters. The index.qmd file is the book’s front matter or preface; references.qmd is a conventional name for the bibliography page, which Quarto appends automatically.
Running quarto render in the project directory builds all declared formats. The HTML output is a complete navigable website with a sidebar showing the book’s structure; the PDF is a typeset book; the EPUB is a properly structured ebook.
16.5.2 Websites
The website project type produces a multi-page HTML site from a collection of QMD files:
project:
type: website
website:
title: "CLI Typography Documentation"
navbar:
left:
- href: index.qmd
text: Home
- href: guide/installation.qmd
text: Guide
- href: reference.qmd
text: Reference
sidebar:
- title: "Guide"
contents:
- guide/installation.qmd
- guide/first-document.qmd
- guide/advanced.qmd
format:
html:
theme: flatly
toc: true
code-copy: true16.5.3 Presentations
Quarto produces presentations in two formats from the same source: HTML slides using Reveal.js and PDF slides using Beamer. The same QMD file can render to both by declaring both in the format section.
---
title: "CLI Typography"
format:
revealjs:
theme: default
slide-number: true
transition: fade
beamer:
theme: metropolis
aspectratio: 169
---Slide breaks are created with ## headings (level 2). The presentation body uses the same Markdown constructs as any Quarto document, plus a few presentation-specific features:
## The problem {.smaller}
::: {.incremental}
- Documents built with GUI tools encourage visual fiddling
- Reproducibility requires scripts, not mouse clicks
- Multiple output formats need automation
:::
## A demonstration {background-color="#2c3e50"}
```{python}
#| echo: true
import pandoc
# Live code in a slide16.6 Two-column layout
Main content in the larger column.
Supporting content in the narrower column.
The `.incremental` class on a list makes items appear one at a time in the HTML presentation.
The `{background-color}` attribute sets the slide's background. The `{.smaller}` class reduces
font size on a specific slide.
## Callouts and special blocks
Quarto provides five types of callout blocks for emphasising content — note, tip, warning, caution,
and important — which render appropriately across formats:
```markdown
::: {.callout-note}
## Note
This is a note callout. It uses blue styling in HTML and a
bordered box in PDF.
:::
::: {.callout-warning}
Always embed fonts before sending a PDF to a printer.
:::
::: {.callout-tip}
## Performance tip
Use `--freeze` in your `_quarto.yml` to cache computation
results across sessions.
:::
The callout type determines the styling: note is blue, tip is green, warning is yellow, caution is orange, and important is red. In PDF output, they render as coloured boxes; in HTML, as styled alert-style blocks; in Word output, as formatted sidebars.
Panel tabsets produce content in multiple tabs in HTML output and as sequential sections in PDF:
::: {.panel-tabset}
### Python
```python
result = sum(range(100))
print(result)16.6.1 R
result <- sum(seq(0, 99))
print(result)16.6.2 Shell
python3 -c "print(sum(range(100)))":::
## Themes and customisation
Quarto's HTML output uses Bootstrap 5 themes. The `theme` key in `format: html` accepts either
a built-in theme name or a list combining a base theme with a custom SCSS file:
```yaml
format:
html:
theme: [cosmo, custom.scss]
The custom SCSS file uses Quarto’s theme variable system:
/*-- scss:defaults --*/
// Typography
$font-family-base: "EB Garamond", Georgia, serif;
$font-size-base: 1.1rem;
$line-height-base: 1.65;
// Headings
$headings-font-family: "Fira Sans", system-ui, sans-serif;
$headings-font-weight: 500;
// Colors
$primary: #1a4e8c;
$body-bg: #ffffff;
$body-color: #1c1c1c;
/*-- scss:rules --*/
// Additional CSS rules
.callout {
border-radius: 4px;
}
code {
font-family: "JetBrains Mono", monospace;
font-size: 0.875em;
}
pre.sourceCode {
background-color: #f8f8f8;
border-left: 3px solid #ddd;
}The /*-- scss:defaults --*/ section sets Bootstrap variable values. The /*-- scss:rules --*/ section adds arbitrary CSS rules that complement rather than override the theme.
For PDF output, the equivalent customisation goes through LaTeX. The include-in-header key injects raw LaTeX into the preamble:
format:
pdf:
documentclass: scrartcl
mainfont: "EB Garamond"
pdf-engine: xelatex
include-in-header:
text: |
\usepackage{microtype}
\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhead[L]{\textit{\leftmark}}
\fancyhead[R]{\thepage}16.7 Extensions
Quarto’s extension system provides pre-packaged formats, filters, and shortcodes. Extensions are installed per-project from GitHub repositories:
# Install an extension
quarto add quarto-ext/lightbox # clickable lightbox for images
quarto add quarto-ext/fontawesome # Font Awesome icons
quarto add quarto-journals/jss # J. Statistical Software format
quarto add quarto-journals/elsevier # Elsevier journal template
quarto add quarto-journals/acm # ACM proceedings formatJournal extensions are the most important category for academic authors. They provide format-specific templates, document class files, and submission-ready output without requiring LaTeX expertise:
---
title: "A Reproducible Analysis"
format:
jss-pdf:
keep-tex: true
jss-html: default
---After installing the JSS extension, jss-pdf and jss-html become available as output formats. The extension handles all the template details; the author writes standard Quarto Markdown.
16.8 Code execution and reproducibility
Quarto’s approach to reproducibility centres on two mechanisms: caching and freezing.
Caching (cache: true in a code block or globally in _quarto.yml) stores execution results on disk. On subsequent renders, cached blocks are not re-executed unless their code changes or their dependencies change. The cache lives in a _cache/ directory alongside the document.
# In _quarto.yml: cache all blocks by default
execute:
cache: trueThe limitation of caching is that it is session-local: the cache is not portable across machines and is not committed to version control. Collaborators rebuilding the document from scratch will re-execute everything.
Freezing (freeze: auto or freeze: true) commits execution results to the _freeze/ directory, which is tracked in version control. When a collaborator without the required Python or R environment renders the document, frozen results are used rather than re-executing:
# In _quarto.yml
execute:
freeze: auto # re-execute only when source changesfreeze: auto is the recommended setting for collaborative projects. It re-runs code when the source changes but uses frozen results otherwise. freeze: true never re-runs, which is appropriate for finalized data that should not change.
The _freeze/ directory should be committed to version control alongside the source. This means contributors who do not have the computational environment installed can still build the full document:
# Full render (re-runs all code)
quarto render --execute
# Render using frozen results only
quarto render # uses _freeze/ where available16.9 Comparison with R Markdown
Quarto supersedes R Markdown, though R Markdown remains functional and widely used. The key differences matter most for authors choosing between them for new projects.
Quarto is multi-language by design: the same syntax and tooling works for Python, R, Julia, and Observable without requiring separate packages (reticulate, JuliaCall, etc.). An R Markdown document that uses Python via reticulate requires a working R environment even though the Python code could run without R; the equivalent Quarto document uses a Jupyter kernel and requires only Python.
Quarto’s chunk option syntax uses the YAML #| style rather than R Markdown’s comma-separated {r, options} style. Both syntaxes work in Quarto for backward compatibility, but #| is preferred because it is consistent, readable, and does not require knowledge of R’s syntax rules for quoting.
Quarto’s cross-reference system is built-in and consistent across output formats, replacing the format-specific systems of bookdown, officedown, and other R Markdown extensions. One syntax works for HTML, PDF, EPUB, and Word.
For existing R Markdown projects, migration to Quarto is straightforward: rename .Rmd to .qmd, update the YAML header to Quarto’s format, and run quarto render. Most documents require minimal changes.
16.10 A complete project workflow
The typical Quarto workflow for a computational document project:
# Create a book project
quarto create-project mybook --type book
cd mybook
# Structure created:
# _quarto.yml
# index.qmd
# intro.qmd
# summary.qmd
# references.bib
# Preview during development (live reload)
quarto preview
# Render all formats
quarto render
# Render specific format
quarto render --to pdf
# Render with fresh execution (ignore freeze)
quarto render --execute
# Publish to GitHub Pages
quarto publish gh-pages
# Publish to Quarto Pub (free hosting)
quarto publish quarto-pubThe quarto preview command is equivalent to make watch from Chapter 10 but integrated: it starts a local web server, opens the document in a browser, and rebuilds on every save. For HTML output, the rebuild is fast; for PDF output, the full LaTeX pipeline runs on every save, which can be slow for large documents. In practice, use quarto preview for HTML drafting and render to PDF for production builds.
Quarto’s position in the tool landscape is clear: if your document involves executable code that generates its content, Quarto is the right tool. Its handling of reproducibility, its multi-format output, and its polished publishing infrastructure are together the best available solution for computational documents. For documents with no computational content, its advantages over plain Pandoc are smaller — the additional YAML configuration and the Quarto layer between Markdown and Pandoc add complexity without adding capability. Chapter 11’s decision framework applies: choose the tool that matches the document.
The next chapter examines Emacs and Org Mode — the oldest and in some ways most powerful system in this part of the book, with a learning curve to match.