# Use Freeze to Cache Expensive Notebooks

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


``` yaml
# 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


``` yaml
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


``` bash
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


``` bash
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


``` bash
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


``` bash
great-docs freeze user_guide/benchmarks.qmd user_guide/mcmc-demo.qmd
```


Or specify a custom persistence directory:


    Terminal


``` bash
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


``` yaml
- 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


``` yaml
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


``` bash
great-docs freeze user_guide/benchmarks.qmd
```


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


    Terminal


``` bash
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


``` yaml
---
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


``` yaml
---
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


``` yaml
---
title: "Live Status"
freeze: false
---
```
