type: decision
status: active
timestamp: 2026-06-20
tags: [decisions, architecture, build, cache, ci, pnpm, github-actions]

Build cache — GitHub Actions cache + pnpm CAS (3-layer strategy)

Three-layer build cache: pnpm, GH Actions cache' global store dedupes deps cross-repo locally. Layer 2: GitHub Actions cache (10\ GB/repo free) keyed by pnpm-lock.yaml hash + Astro build cache keyed by source\ hash. Layer 3: Turbo Remote Cache + Bazel REJECTED — Vercel signup + card\ / overengineering.

Build cache — GitHub Actions cache + pnpm CAS

Decision

The family’s build-cache strategy is three layers, picked by locality:

Layer 1 — pnpm content-addressable global store (per-developer-machine)

Already in use family-wide via rules/development/use-pnpm.md. pnpm hard-links every package version exactly once into ~/.pnpm-store/ (or %LOCALAPPDATA%\pnpm on Windows) and symlinks into each node_modules/. Cross-repo dedup: one library version downloaded once across all 11 sites + N packages on a developer’s machine. Cleared only when disk pressure (or via pnpm store prune).

Layer 2 — GitHub Actions cache (per-repo, free 10 GB)

Two cache buckets per repo:

A) pnpm store cache

- name: Cache pnpm store
  uses: actions/cache@v4
  with:
    path: ${{ steps.pnpm-store.outputs.path }}
    key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
    restore-keys: |
      ${{ runner.os }}-pnpm-store-

Exact-match by lockfile hash; fuzzy-fallback to most-recent pnpm-store- cache when the lockfile changes (warm-start the new hash bucket from the previous one).

B) Astro build cache

- name: Cache Astro build
  uses: actions/cache@v4
  with:
    path: |
      node_modules/.astro
      .astro
    key: ${{ runner.os }}-astro-${{ hashFiles('astro.config.*', 'src/**/*', 'public/**/*') }}
    restore-keys: |
      ${{ runner.os }}-astro-

Keyed by config + source-tree hash so source edits invalidate but unrelated repo changes don’t.

Layer 3 — REJECTED for now

Why

Implications

CI workflow shape

The per-site CI template at

already implements Layer 2 part A (pnpm store cache, lockfile-keyed, fuzzy fallback). The template now also documents the strategy in a header comment + adds Astro cache (Layer 2 part B) where the site ships an Astro build.

The per-site CI runbook covers applying the template to all 11 site repos + the package repos that also need cache + the cross-link to this decision.

Monorepo posture

The master oriz/ repo is a polyrepo-as-submodules pattern (infrastructure/chrome-extensions-as-submodules.md

The pnpm workspace is per-repo (each site’s repo + each package’s repo); there is NO master root pnpm-workspace.yaml covering the whole family. This is intentional and aligns with rules/development/repos-work-independently.md.

Cache hygiene

What we measure (light-touch)

What we don’t do

Cross-refs


Edit on GitHub · Back to index