CircleCI restore_cache Always Misses - Fix Cache Keys
Your restore_cache never finds a hit, so every run reinstalls dependencies from scratch. The keys are non-deterministic, point at the wrong file, or don’t match what save_cache wrote.
What this error means
Logs show "No cache found for key ..." on every build, and install steps take full time each run. The cache is being saved but never restored because the lookup key differs from the saved key.
restore_cache
- Searching for cache key: deps-v1-a1b2c3...
- No cache found for the given key(s)
save_cache
- Saving cache deps-v1-d4e5f6...Common causes
A key that changes every run
Embedding {{ .Revision }}, {{ epoch }}, or {{ .BuildNum }} in the key makes it unique per commit/run, so a restore can never match a prior save.
Checksum over a file that is not the lockfile
{{ checksum "package.json" }} changes for unrelated edits; it should checksum the lockfile (package-lock.json, yarn.lock, poetry.lock) that actually pins dependencies.
save and restore keys do not align
If save_cache writes one prefix and restore_cache searches another, or the partial restore keys don’t overlap, the lookup falls through to a miss.
How to fix it
Use a deterministic, lockfile-based key with fallbacks
steps:
- restore_cache:
keys:
- deps-v1-{{ checksum "package-lock.json" }}
- deps-v1-
- run: npm ci
- save_cache:
key: deps-v1-{{ checksum "package-lock.json" }}
paths:
- ~/.npmKeep save and restore keys identical
- Use the exact same templated key string in
save_cache.keyand the firstrestore_cache.keysentry. - Checksum the lockfile, not the manifest.
- Bump the static prefix (
v1→v2) to intentionally invalidate the cache.
How to prevent it
- Key caches on the lockfile checksum, never on revision/epoch.
- Mirror the save key as the first restore key, with a prefix fallback.
- Version the key prefix so you can invalidate on purpose.