A continuous integration pipeline that takes twelve minutes when it could take three is a tax paid on every pull request by every engineer, several times a day. Caching is the usual fix, and caching is also the thing most teams configure once from a template and never inspect again — which is how you end up with a cache that misses on every run while still paying the cost of trying.
The fix starts with measurement, not with more caching.
What changed in 2026
- Remote build caches spread beyond large monorepos. Content-addressed caching shared across machines and developers became accessible to smaller teams through hosted services and build tools.
- Cache hit rate became a tracked metric. Platforms began surfacing hit rates directly, which revealed how many pipelines had caches that never hit.
- Container build caching improved. Better cache export and import options made layer caching across ephemeral runners considerably more effective.
- Cost pressure sharpened focus. As CI minutes became a visible budget line, build time optimization moved from developer-experience nicety to cost reduction.
What to cache and how to key it
| Target |
Key on |
Restore prefix |
| Dependency store |
Lockfile hash plus runtime version |
Runtime version alone |
| Compiled build artifacts |
Content hash of inputs |
Usually none; exact or nothing |
| Container layers |
Dockerfile plus dependency manifest hash |
Base image tag |
| Test fixtures or datasets |
Fixture version identifier |
Fixture major version |
| Linter and type-check caches |
Config hash plus source tree state |
Config hash |
The two-part pattern — exact key plus restore prefix — is the single most important technique. The exact key includes the lockfile hash, so an unchanged dependency set restores everything. The restore prefix omits the lockfile hash, so when dependencies do change you still restore the previous cache and only download what is new. Without the prefix, any dependency change means a completely cold install.
Cache the package manager's store rather than the installed directory where the tooling supports it. Stores are content-addressed, deduplicate across projects, and re-linking from a warm store is typically faster than restoring a large installed tree.
Measuring before optimizing
Look at the actual hit rate first. A pipeline restoring a cache on every run that never matches is paying download cost, upload cost, and full install cost. That is a net loss over no caching, and it is common.
Then look at where the time actually goes. Teams frequently optimize dependency installation while the real cost sits in a test suite that runs everything on every change, or in a container build that invalidates its layers because the source copy happens before the dependency install. Reordering a Dockerfile so dependency installation precedes source copy is often a bigger win than any cache tuning.
Watch out for cross-branch staleness. Caching build outputs keyed on branch name rather than content hash produces failures where a build succeeds with an artifact that does not match the source. Those take a long time to diagnose because the symptom appears far from the cause. Content-addressed keys eliminate the class entirely.
For the deployment side of the pipeline, zero-downtime deployment covers what happens after the build passes, and trunk-based development covers the branching model that makes fast pipelines matter most.
Common mistakes
- No restore prefix. Every dependency change becomes a full cold install.
- Caching by branch name. Produces stale artifacts and confusing failures.
- Caching a directory the tool regenerates anyway. Verify the cache is actually being used, not just restored.
- Ignoring cache size limits. Platforms evict caches; an oversized cache may be evicted before its next use.
- Optimizing the wrong stage. Profile the pipeline before tuning. The bottleneck is often tests, not installation.
- Never invalidating. A cache that cannot be cleared becomes a source of unreproducible builds.
FAQ
How do I know if my cache is hitting?
Most platforms log cache hit or miss explicitly. If yours does not surface it in a dashboard, the raw job logs will say.
Should I cache the test suite results?
Test result caching, where unchanged code skips unchanged tests, is powerful and requires a build system that tracks dependencies precisely enough to be safe. Do not approximate it manually.
Is Docker layer caching worth it on ephemeral runners?
Yes, with cache export to a registry or remote backend. Without an external cache target, ephemeral runners start cold every time.
How large should a cache be?
Small enough to download faster than rebuilding. A very large cache can take longer to restore than the work it saves.
Where to go next
For the branching model, read trunk-based development. For deploying what you built, zero-downtime deployment, and for isolated test databases in the same pipeline, database branching explained.