Caching TechDocs Builds in CI

TechDocs rebuilds every docs site from source on each push, and on a monorepo with hundreds of docs that turns into minutes of CI burned re-rendering pages that never changed. Caching the build — keying on content hashes and reusing prior output — cuts that to seconds for the unchanged majority. This how-to sets up content-addressed caching for TechDocs in CI. It extends TechDocs & Documentation Pipelines within Developer Portal Architecture & Frameworks.

Prerequisites

  • A working TechDocs pipeline that builds docs in CI and publishes to external storage (S3, GCS, or Azure Blob).
  • CI with a cache mechanism — GitHub Actions cache, GitLab cache, or a shared artifact store.
  • Docs sources under version control so content hashes are stable and computable.
  • The techdocs-cli available in the CI image.
Prerequisites for TechDocs caching A working pipeline, a CI cache, versioned sources, and techdocs-cli enable content-addressed caching. TechDocs pipeline CI cache store versioned sources techdocs-cli Fast rebuilds skip unchanged
A content hash of each docs directory is the cache key — the same sources always produce the same key, so unchanged docs hit the cache.

Exact Configuration

  1. Compute a content hash per docs directory and use it as the cache key.

    # Requires git, sha256sum
    # Hash only the docs sources for one component
    DOCS_HASH=$(git ls-files docs mkdocs.yml | xargs sha256sum | sha256sum | cut -c1-16)
    echo "techdocs-${DOCS_HASH}"
    
  2. Restore-or-build in CI. Skip the build when the cache holds output for this hash.

    # .github/workflows/techdocs.yml
    # Requires actions/cache >= v4
    - uses: actions/cache@v4
      id: techdocs-cache
      with:
        path: site/
        key: techdocs-${{ hashFiles('docs/**', 'mkdocs.yml') }}
    - name: Build TechDocs
      if: steps.techdocs-cache.outputs.cache-hit != 'true'
      run: techdocs-cli generate --no-docker
    
  3. Publish either way so the storage bucket always has the current output, cache hit or miss.

    # Requires techdocs-cli
    techdocs-cli publish --publisher-type awsS3 \
      --storage-name "$DOCS_BUCKET" --entity default/component/payments
    
Restore-or-build flow The content hash is looked up; a hit restores prior output and skips the build, a miss builds and repopulates the cache. content hash cache lookup HIT → restore skip build MISS → build repopulate publish to storage
Publish runs on both branches — the cache saves the build step, but storage must stay current whether or not a rebuild happened.

Validation

# Requires CI logs / timing
# 1. An unchanged docs push hits the cache
#    Push with no docs change; confirm the build step is skipped
grep -q "Cache restored" ci.log && echo "cache hit on unchanged docs"
# Expected: cache hit on unchanged docs

# 2. A docs change misses the cache and rebuilds
#    Edit one page; confirm the build ran
grep -q "Building documentation" ci.log && echo "rebuilt on change"
# Expected: rebuilt on change

# 3. Published output matches the current sources
techdocs-cli publish --dry-run --entity default/component/payments
# Expected: uploads reflect the latest content
TechDocs caching validation checks Unchanged docs hit the cache, changed docs rebuild, and published output matches current sources. Unchanged → hit build skipped Changed → miss rebuilds Output current matches sources
The two-sided test matters: a cache that never misses on a real change is silently serving stale docs.

Edge Cases & Troubleshooting

Symptom Root Cause Resolution
Stale docs served after an edit Hash omits a changed input Include every source in the hash: docs/**, mkdocs.yml, theme
Cache never hits Key includes volatile data (timestamps, commit SHA) Key only on content, not on run metadata
Cache hits but storage stale Publish gated behind the cache-miss branch Always publish, regardless of cache outcome
Cache grows unbounded No eviction of old hashes Rely on the CI cache’s LRU eviction; scope keys per component
Shared macros change nothing Included partials not hashed Add shared includes to the hashed input set
TechDocs caching pitfalls by class Stale output and shared-macro misses are hash-coverage issues; never-hitting and stale-storage are keying and publish issues. Hash coverage stale output macro miss → hash all inputs Keying & publish never hits stale storage → content key + always publish
The dangerous failure is a hash that misses a real input — it serves confidently wrong docs, so err toward hashing too much.

Frequently Asked Questions

Should I cache the build output or the rendered site?

Cache the rendered site/ output keyed on the source hash. The expensive step is rendering markdown to HTML, so caching the result of that step is where the time is saved. Caching intermediate build state is fiddlier and buys less, because the render still has to run.

Does per-component caching help a monorepo?

Enormously. Scope the cache key per component so editing one team’s docs invalidates only that component, leaving the other hundreds as cache hits. A single site-wide key would rebuild everything on any change, which defeats the purpose on a large monorepo.