Use Freeze to Cache Expensive Notebooks

Avoid re-executing costly computations (MCMC, deep learning, simulations) on every docs build using Quarto’s freeze feature.

If your documentation includes computationally expensive notebooks you can use Quarto’s freeze feature to persist execution outputs and skip re-execution on subsequent builds.

The Problem

Without freeze, every great-docs build re-executes all .qmd notebooks from scratch. For projects with heavy computations this might mean:

  • 30–45 minute CI runs on every PR
  • fragile builds (transient sampling failures break unrelated PRs)
  • painful local iteration (every build is a cold start)

The Solution

Quarto’s freeze stores executed outputs in a _freeze/ directory. Once frozen, notebooks are only re-executed when their source changes (with freeze: auto) or never during project renders (with freeze: true).

Great Docs integrates this natively. Just set freeze in your config:

great-docs.yml
# Cache computational outputs across builds
freeze: auto

How It Works

  1. freeze: auto adds execute: freeze: auto to the generated _quarto.yml re-execution occurs only when the source has changed.

  2. Great Docs automatically injects a pre-render hook that restores _freeze/ into the build directory before rendering. No extra scripts or configuration needed.

  3. Because Great Docs recreates the build directory on each build, this automatic restoration ensures the freeze cache is always available when Quarto looks for it.

Step-by-Step Setup

1. Enable freeze in great-docs.yml

great-docs.yml
freeze: auto

This setting means that no pre-render scripts need be created or managed.

2. Run the initial freeze

Execute your expensive page(s) and capture their outputs:

Terminal
great-docs freeze user_guide/benchmarks.qmd

3. Commit _freeze/ to version control

The great-docs freeze command automatically persists the cache to your project root. Just commit it:

Terminal
git add _freeze/
git commit -m "Persist freeze cache for docs builds"

Now subsequent builds (locally and in CI) will restore the cache and skip re-execution.

Updating the Freeze Cache

When you change a frozen page’s source code or input data, use the great-docs freeze command to re-execute it and update the cache:

Terminal
great-docs freeze user_guide/benchmarks.qmd

This command:

  1. Renders the specified page inside the build directory (always executing code)
  2. Copies the updated _freeze/ entries back to your project root
  3. Tells you exactly what to commit

You can freeze multiple pages at once:

Terminal
great-docs freeze user_guide/benchmarks.qmd user_guide/mcmc-demo.qmd

Or specify a custom persistence directory:

Terminal
great-docs freeze user_guide/benchmarks.qmd --freeze-dir docs/_freeze

The command prints a ready-to-use git add + git commit hint when it finishes.

CI Workflow

In your GitHub Actions workflow, the freeze cache is automatically available because it’s checked into the repo:

.github/workflows/docs.yml
- name: Build docs
  run: great-docs build

No extra CI cache steps are needed as _freeze/ is in the repo and Great Docs handles the rest.

Advanced: Additional Pre-render Scripts

If you need custom scripts to run before rendering (e.g., data generation), add them via pre_render. Great Docs automatically runs the freeze restore before your scripts so you don’t need to include it yourself:

great-docs.yml
freeze: auto
pre_render:
  - scripts/generate-data.py

Scripts run in order after the freeze restore, and each must exist at the specified path relative to your project root.

When to Re-execute

The freeze cache should be refreshed when:

  • Input data changes (not just source code)
  • Package API changes affect output
  • You want to update rendered figures or tables

To re-execute specific pages:

Terminal
great-docs freeze user_guide/benchmarks.qmd

To force a full re-execution of all frozen pages, use --clean:

Terminal
great-docs freeze --clean user_guide/benchmarks.qmd user_guide/sampling.qmd

Build Log

When freeze is configured, the build log reports it:

 Step 1  Prepare build directory ················· Ready
          Freeze mode: auto

This confirms that the freeze configuration is active and the cache restore will happen automatically.

Page-Level Freeze

You don’t have to freeze your entire site. If only one or two pages are expensive (e.g., a benchmarks page), use page-level freeze by adding freeze: to that page’s YAML frontmatter:

user_guide/benchmarks.qmd
---
title: "Benchmarks"
freeze: auto
---

# Benchmarks

This page runs extensive MCMC sampling that takes ~20 minutes...

Great Docs automatically normalizes this shorthand into the nested form Quarto requires (execute: freeze: auto) during the build. You can also use the full Quarto syntax if you prefer:

user_guide/benchmarks.qmd
---
title: "Benchmarks"
execute:
  freeze: auto
---

Both forms are equivalent.

With page-level freeze only (no project-wide freeze: key), Great Docs still automatically restores _freeze/ when any page has freeze frontmatter. However, to ensure the restore runs reliably, set freeze: auto project-wide (it has no effect on pages without the freeze frontmatter key).

This way:

  • Most pages render fresh on every build (picking up code changes immediately)
  • Frozen pages (like benchmarks.qmd) skip execution unless their source changes
  • The cache restore happens automatically (no extra scripts needed)

Which pages are cached?

The _freeze/ directory stores outputs per-page. After a build, you’ll see entries like:

_freeze/
└── user_guide/
    └── benchmarks/
        └── execute-results/
            └── html.json

Only pages with freeze: (or execute: freeze:) in their frontmatter produce entries here. Commit only those entries to version control.

Mixing project-level and page-level

You can also combine both approaches:

  • Set freeze: auto project-wide (all pages frozen by default)
  • Override specific pages with freeze: false in their frontmatter to force re-execution
a-page-that-must-always-execute.qmd
---
title: "Live Status"
freeze: false
---