Skip to content

jagatsingh/quarto-book-template

Repository files navigation

Quarto Technical Book Template

A working template for writing technical books with executable code examples, tested snippets, infrastructure via Docker Compose, and automated CI validation.

Read the full write-up:

Starting a New Book from This Template

Step 1: Fork or clone the template

# Option A: Fork on GitHub (recommended — keeps link to upstream for updates)
# Click "Fork" on https://github.com/jagatsingh/quarto-book-template

# Option B: Clone and re-initialize
gh repo create my-book --private
git clone https://github.com/jagatsingh/quarto-book-template my-book
cd my-book
git remote set-url origin https://github.com/yourusername/my-book.git
git push -u origin main

Step 2: Update book metadata

Edit _quarto.yml:

book:
  title: "Your Book Title"
  subtitle: "A subtitle for your book"
  author: "Your Name"
  date: today
  chapters:
    - index.qmd
    - chapters/01-your-first-chapter.qmd
    - chapters/02-your-second-chapter.qmd

Step 3: Replace the example content

  1. Edit index.qmd — your book's introduction
  2. Delete the example chapters, create your own in chapters/
  3. Replace code/ch01/ and code/ch02/ with your own tested code
  4. Update docker-compose.yml with the infrastructure your book needs
  5. Update scripts/start-infra.sh and stop-infra.sh accordingly

Step 4: Install and render

uv sync
pre-commit install
QUARTO_PYTHON=.venv/bin/python quarto render

What This Template Demonstrates

  • Executable code blocks in Chapter 2 that connect to a real Postgres database and capture live output
  • Snippet extraction in Chapter 1 from a tested code repository with CI validation
  • Mermaid diagrams rendered inline in chapters
  • Cross-references (@sec-, @fig-, @tbl-, @lst-) that survive chapter reordering
  • Snippet linter that catches broken references and dead snippets
  • Docker Compose infrastructure started automatically via Quarto pre-render hooks
  • GitHub Actions CI that validates everything: snippets, tests, and full book render
  • uv for fast, reproducible Python dependency management

Prerequisites

Quick Start

# Clone the template
gh repo clone jagatsingh/quarto-book-template
cd quarto-book-template

# Install Python dependencies
uv sync

# Install pre-commit hooks
pre-commit install

# Start infrastructure, render book
quarto render

# The pre-render hook starts Docker Compose automatically.
# Output is in _book/ (HTML) and _book/*.pdf (PDF).

Project Structure

_quarto.yml                        # Book config with pre/post render hooks
chapters/
  index.qmd                        # Introduction
  01-infrastructure-setup.qmd      # Snippets from tested repo (eval: false)
  02-working-with-data.qmd         # Inline executable code (eval: true)
code/
  ch01/
    schema.py                      # Schema creation with snippet markers
    seed.py                        # Seed data with snippet markers
  tests/
    test_ch01.py                   # Tests for infrastructure code
    test_ch02.py                   # Tests for query examples
diagrams/                          # Draw.io/Excalidraw sources (add .drawio files here)
scripts/
  start-infra.sh                   # Pre-render: docker compose up + schema + seed
  stop-infra.sh                    # Post-render: docker compose down
  lint_snippets.py                 # CI: validate snippet references
  export-diagrams.sh               # CI: Draw.io → SVG export
docker-compose.yml                 # Postgres 17 (pinned by SHA256 digest)
pyproject.toml                     # Python dependencies (managed by uv)
.pre-commit-config.yaml            # Pre-commit hooks (lint, format, secrets, snippets)
renovate.json5                     # Dependency updates with 7-day delay
.github/workflows/book.yml         # Full CI pipeline

Commands

# Render the book (starts infra automatically)
quarto render

# Render with live preview (watches for changes)
quarto preview

# Run tests against running infrastructure
docker compose up -d --wait
uv run python code/ch01/schema.py
uv run python code/ch01/seed.py
uv run pytest -v
docker compose down

# Lint snippet references
uv run python scripts/lint_snippets.py

# Export Draw.io diagrams to SVG
scripts/export-diagrams.sh

Customizing the PDF Output

All PDF customization goes in the typst-pdf section of _quarto.yml.

Font size

format:
  typst-pdf:
    fontsize: 11pt          # Default is 10pt. Common book sizes: 10pt, 11pt, 12pt

Font family

format:
  typst-pdf:
    mainfont: "Linux Libertine"    # Serif font for body text
    sansfont: "Linux Biolinum"     # Sans font for headings
    monofont: "Fira Code"          # Monospace font for code blocks

Common combinations for technical books:

Style mainfont monofont Notes
Classic Linux Libertine Fira Code Open source, elegant
Modern Inter JetBrains Mono Clean, highly legible
O'Reilly style Georgia Consolas Familiar to tech readers
Default (Typst default) (Typst default) Works well out of the box

Page size and margins

format:
  typst-pdf:
    papersize: a4            # Options: a4, us-letter, us-trade (6x9in)
    margin:
      x: 1in                 # Left and right margins
      y: 1in                 # Top and bottom margins
      # Or set individually:
      # top: 1in
      # bottom: 1in
      # left: 1.2in
      # right: 0.8in

Common book sizes:

Format papersize Typical use
A4 a4 International standard, online distribution
US Letter us-letter North American printing
US Trade us-trade Standard book size (6"x9"), Amazon KDP

Code block styling

format:
  typst-pdf:
    code-overflow: wrap        # Wrap long lines instead of clipping
    code-line-numbers: true    # Show line numbers in code blocks
    code-block-bg: "#f5f5f5"   # Background color for code blocks

Figure and diagram sizing

format:
  typst-pdf:
    fig-width: 5.5             # Default figure width in inches
    fig-height: 3.5            # Default figure height in inches

Override per-diagram in the .qmd file:

```{mermaid}
%%| fig-width: 4
%%| fig-height: 3
flowchart TD
    A --> B --> C
```

Table of contents

book:
  toc: true                    # Enable TOC (default for books)
  toc-depth: 3                 # How many heading levels to include

Full customization example

format:
  typst-pdf:
    papersize: us-trade
    fontsize: 11pt
    mainfont: "Linux Libertine"
    monofont: "Fira Code"
    margin:
      x: 0.8in
      y: 1in
    fig-width: 4.5
    fig-height: 3
    code-overflow: wrap
    code-line-numbers: true

For advanced Typst customization (custom headers, footers, title pages), see the Quarto Typst documentation.

Adding a New Chapter

  1. Create chapters/03-new-chapter.qmd with YAML frontmatter:

    ---
    title: "Your Chapter Title"
    id: sec-your-chapter
    ---
  2. Add it to _quarto.yml under book.chapters

  3. Use @sec-your-chapter cross-references from other chapters

  4. For infrastructure-dependent code: add snippet markers in code/ch03/, reference with eval: false

  5. For self-contained code: write inline executable {python} blocks

  6. Run QUARTO_PYTHON=.venv/bin/python quarto render to verify

Adding Diagrams

Mermaid (preferred for simple diagrams): write inline in .qmd files:

```{mermaid}
%%| label: fig-my-diagram
%%| fig-cap: "Description"
%%| fig-width: 4
flowchart TD
    A --> B --> C
```

Draw.io (for complex architecture diagrams):

  1. Create diagrams/my-diagram.drawio
  2. Run scripts/export-diagrams.sh to generate SVG
  3. Reference in chapter: ![Caption](../diagrams/my-diagram.svg){#fig-my-diagram}

Tips for PDF-friendly diagrams:

  • Use flowchart TD (top-down) instead of LR (left-right) for narrow pages
  • Set fig-width: 4 or fig-width: 4.5 to keep diagrams within margins
  • Keep participant names short in sequence diagrams (C as Client, not participant Client)
  • ERD diagrams with many columns can be tall — consider splitting into multiple diagrams

CI Pipeline

The GitHub Action (.github/workflows/book.yml) runs on every push and PR:

  1. Pre-commit checks — linting, formatting, secrets detection
  2. Lint snippets — broken references fail the build
  3. Export diagrams — regenerate SVGs from Draw.io sources
  4. Start Postgres — Docker Compose with health check
  5. Run tests — pytest validates all code examples
  6. Render book — Quarto executes inline code, resolves snippet includes
  7. Upload artifacts — PDF and HTML available as build artifacts
  8. Create release — on push to main, publishes PDF as a GitHub Release

When Renovate or Dependabot bumps a dependency, the full pipeline runs — catching breakage before merge.

Recommended Tooling

VS Code Extensions

Extension Purpose
Quarto .qmd syntax highlighting, preview, cell execution, YAML intellisense
Mermaid Markdown Syntax Highlighting Syntax highlighting for Mermaid code blocks
Draw.io Integration Edit .drawio files directly in VS Code
Python Python language support, debugging, linting
Jupyter Required by the Quarto extension for executing Python cells
Docker Docker Compose management, container logs
YAML YAML validation for _quarto.yml and docker-compose.yml
markdownlint Markdown linting (also catches issues in .qmd files)
GitLens Git blame, history, and diff for tracking chapter changes

VS Code Settings

Add to your workspace .vscode/settings.json:

{
  "files.associations": {
    "*.qmd": "quarto"
  },
  "[quarto]": {
    "editor.wordWrap": "on",
    "editor.rulers": [100]
  },
  "quarto.render.renderOnSave": false
}

Other Recommended Tools

  • uv — fast Python package manager, replaces pip/venv
  • pre-commit — git hook manager for automated checks on every commit
  • Quarto CLI — the book build tool
  • Draw.io Desktop — standalone diagram editor (also available as VS Code extension above)
  • Excalidraw — browser-based hand-drawn style diagrams
  • D2 — text-based diagramming for complex layouts

Pre-commit Hooks

This template includes pre-commit hooks that run automatically on every git commit:

# Install hooks (one-time setup)
pre-commit install

# Run all hooks manually
pre-commit run --all-files

Included Hooks

Hook What it does
trailing-whitespace Strips trailing whitespace from code files
end-of-file-fixer Ensures files end with a newline
check-yaml Validates YAML syntax (_quarto.yml, docker-compose.yml)
check-added-large-files Blocks files over 500KB (catches accidentally committed binaries)
check-merge-conflict Prevents committing unresolved merge conflict markers
detect-private-key Blocks accidental commits of private keys
gitleaks Scans for hardcoded secrets, API keys, and tokens
ruff Python linting and auto-fixing (replaces flake8, isort, pyupgrade)
ruff-format Python code formatting (replaces black)
lint-snippets Validates all snippet references resolve correctly (custom local hook)

The snippet linter runs on every commit that touches .qmd or .py files, catching broken references before they reach CI.

Why These Hooks Matter for a Book

Technical books have a larger attack surface for quality issues than typical code:

  • Secrets in code examples — it's easy to paste a real connection string into a chapter. gitleaks and detect-private-key catch this.
  • Stale snippets — the snippet linter prevents broken include directives from reaching readers.
  • Inconsistent formattingruff-format ensures all Python examples in the book follow the same style. Readers notice when Chapter 3 uses single quotes and Chapter 7 uses double quotes.
  • Large files — accidentally committing a rendered PDF or database dump bloats the repo permanently. The size check prevents this.

Supply Chain Security

This template includes supply chain protections: 7-day Renovate delay on dependency upgrades (renovate.json5), Docker images pinned by SHA256 digest, and locked dependencies via uv.lock. See the full write-up on supply chain security for the rationale and implementation details.

License

MIT

About

Template for technical books with Quarto, executable code, Example book with Postgres, pre-commit hooks, and release workflow

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors