Slashing CI Times With Smart Caching in GitHub Actions
1 min read
The setup
A TypeScript monorepo with 5 packages, using pnpm workspaces. Every push ran pnpm install (2 min) and pnpm build (8 min) from scratch.
The cache strategy
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: ~/.pnpm-store
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: pnpm-
- name: Cache build output
uses: actions/cache@v4
with:
path: packages/*/dist
key: build-${{ github.sha }}
restore-keys: build-
The results
| Step | Before | After |
|---|---|---|
| Install | 2m 12s | 8s |
| Build | 8m 30s | 1m 05s |
| Lint+Test | 1m 30s | 1m 30s |
| Total | 12m 12s | 2m 43s |
What I learned
The restore-keys fallback is the most important part. If the lockfile changes, you don’t want a full cache miss — you want a partial restore. The difference between 12 minutes and 2 minutes is the difference between “I’ll check back later” and “I’ll wait for green.”