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 keys in 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-keys not 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. 1.Review the current cache key configuration: Check how keys are generated.
  2. 2.```yaml
  3. 3.- uses: actions/cache@v4
  4. 4.with:
  5. 5.path: ~/.npm
  6. 6.key: npm-${{ hashFiles('package-lock.json') }}-${{ github.sha }}
  7. 7.# Problem: github.sha changes every commit, preventing cache hits
  8. 8.`
  9. 9.Add restore-keys for partial matching: Allow fallback to similar caches.
  10. 10.```yaml
  11. 11.- uses: actions/cache@v4
  12. 12.with:
  13. 13.path: ~/.npm
  14. 14.key: npm-${{ hashFiles('package-lock.json') }}-${{ github.sha }}
  15. 15.restore-keys: |
  16. 16.npm-${{ hashFiles('package-lock.json') }}-
  17. 17.npm-
  18. 18.`
  19. 19.Simplify the cache key to improve hit rate: Remove overly specific components.
  20. 20.```yaml
  21. 21.- uses: actions/cache@v4
  22. 22.with:
  23. 23.path: ~/.npm
  24. 24.key: npm-${{ hashFiles('package-lock.json') }}
  25. 25.restore-keys: |
  26. 26.npm-
  27. 27.`
  28. 28.Verify cache is being hit after the fix: Check workflow logs.
  29. 29.`
  30. 30.# In workflow run logs, look for:
  31. 31.# "Cache restored from key: npm-abc123"
  32. 32.# Instead of:
  33. 33.# "Cache not found for input keys"
  34. 34.`
  35. 35.Monitor cache hit rates: Track improvement over time.
  36. 36.```yaml
  37. 37.- name: Report cache status
  38. 38.if: always()
  39. 39.run: |
  40. 40.echo "Cache hit: ${{ steps.cache.outputs.cache-hit }}"
  41. 41.`

Prevention

  • Always configure restore-keys with 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