How Lithosphere CI pipelines use caching to keep PR times under 10-15 minutes.
Cache Layers
Layer
Tool
Key
TTL
Workflow
pnpm store
actions/cache
os-pnpm-store-{lockfile hash}
7 days (LRU)
ci.yaml
node_modules
actions/cache
os-node-modules-{lockfile hash}
7 days (LRU)
ci.yaml
Turborepo local
actions/cache
os-turbo-{sha}
7 days (LRU)
ci.yaml
Docker layers
BuildKit GHA cache
type=gha
repo-scoped
publish-images.yaml
Hardhat cache
pnpm store (includes hardhat cache dir)
lockfile-based
per-install
ci-contracts.yaml
Foundry cache
Not cached in CI (fast enough)
N/A
N/A
ci-contracts.yaml
How It Works
pnpm Store Cache
The pnpm content-addressable store is cached between runs. On cache hit, pnpm install --frozen-lockfile resolves in ~3 seconds instead of 30+.
-name:Get pnpm store directoryrun:echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV-uses:actions/cache@v4with:path:${{ env.STORE_PATH }}key:${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}restore-keys:${{ runner.os }}-pnpm-store-
Turborepo Cache
Turbo hashes each task's inputs (source files, dependencies, env vars) and skips unchanged packages. The .turbo directory is cached between CI runs so even cross-PR builds benefit from prior results.
Docker Layer Cache
docker/build-push-action uses GitHub Actions cache backend (type=gha) for BuildKit layer caching. This makes incremental image builds 2-5x faster.
Hardhat Compilation Cache
Hardhat's cache/ directory stores compilation results. When source files haven't changed, hardhat compile is a no-op. This is included in the pnpm workspace install and cached via node_modules.
Cache Invalidation
pnpm store: Invalidated when any pnpm-lock.yaml changes (new deps)
node_modules: Same as pnpm store
Turbo: Keyed by commit SHA; restore-keys prefix allows partial hits from prior commits
Docker: Invalidated per-layer when Dockerfile or COPY sources change
Parallelization Strategy
The CI is split into independent parallel jobs:
Flaky Test Quarantine
When a test is identified as flaky:
Add skip annotation with a tracking issue link
Move to a __flaky__/ directory (excluded from CI by default)
Run flaky tests in a separate non-blocking job
Fix and re-enable within one sprint
Turbo's inputs config means only changed packages re-run tests, which naturally reduces flake exposure.