Introduction
GitHub Actions cache uses exact key matching by default. If the exact cache key does not match any existing cache entry, the cache restore returns a miss and the workflow must rebuild everything from scratch. Without restore-keys fallback configuration, even a near-match (e.g., same dependencies with a different commit hash) results in a full rebuild, significantly slowing down workflow execution.
Symptoms
- Cache step shows
Cache not found for input keysin workflow logs - Build times are consistently slow because cache is never hit
- Cache key includes a commit hash that changes on every commit
- Dependency installation runs from scratch on every workflow run
- Warning message:
Cache not found for keys: npm-abc123
Common Causes
- Cache key includes a unique value like commit SHA or timestamp
restore-keysnot configured, so partial matches are not used- Cache entry expired (GitHub caches are evicted after 7 days of no access)
- Cache key hash function changed, producing different keys for the same content
- Branch-specific cache not available on new branches
Step-by-Step Fix
- 1.Review the current cache key configuration: Check how keys are generated.
- 2.```yaml
- 3.- uses: actions/cache@v4
- 4.with:
- 5.path: ~/.npm
- 6.key: npm-${{ hashFiles('package-lock.json') }}-${{ github.sha }}
- 7.# Problem: github.sha changes every commit, preventing cache hits
- 8.
` - 9.Add restore-keys for partial matching: Allow fallback to similar caches.
- 10.```yaml
- 11.- uses: actions/cache@v4
- 12.with:
- 13.path: ~/.npm
- 14.key: npm-${{ hashFiles('package-lock.json') }}-${{ github.sha }}
- 15.restore-keys: |
- 16.npm-${{ hashFiles('package-lock.json') }}-
- 17.npm-
- 18.
` - 19.Simplify the cache key to improve hit rate: Remove overly specific components.
- 20.```yaml
- 21.- uses: actions/cache@v4
- 22.with:
- 23.path: ~/.npm
- 24.key: npm-${{ hashFiles('package-lock.json') }}
- 25.restore-keys: |
- 26.npm-
- 27.
` - 28.Verify cache is being hit after the fix: Check workflow logs.
- 29.
` - 30.# In workflow run logs, look for:
- 31.# "Cache restored from key: npm-abc123"
- 32.# Instead of:
- 33.# "Cache not found for input keys"
- 34.
` - 35.Monitor cache hit rates: Track improvement over time.
- 36.```yaml
- 37.- name: Report cache status
- 38.if: always()
- 39.run: |
- 40.echo "Cache hit: ${{ steps.cache.outputs.cache-hit }}"
- 41.
`
Prevention
- Always configure
restore-keyswith progressively broader fallback patterns - Base cache keys on lock file hashes, not commit SHAs or timestamps
- Use separate cache keys for different build configurations (OS, Node version, etc.)
- Monitor cache hit rates and investigate when they drop below 50%
- Implement a cache warming strategy for new branches and environments
- Document cache key strategy in the repository's contributing guide