Skip to content
Latchkey

CI Caching Explained: Speed Up Pipelines Without Breaking Them

Caching is the highest-leverage way to speed up CI - and a common source of subtle, hard-to-debug failures when keys are wrong.

Most CI time is spent re-doing work that has not changed: downloading the same dependencies, rebuilding the same layers. Caching stores those outputs and restores them on the next run. Done right it cuts minutes off every job; done wrong it serves stale data or silently never hits.

What is worth caching

  • Dependency directories (node_modules, ~/.m2, ~/.cargo, pip wheels).
  • Build outputs and compiler caches (incremental builds, ccache).
  • Docker layers via a registry-backed layer cache.

Cache keys and restore keys

A cache key should change exactly when the cached content should change - typically a hash of your lockfile. Restore keys provide a fallback prefix so a near-miss still restores a useful older cache instead of nothing. Too-broad a key serves stale data; too-narrow a key never hits.

GitHub Actions cache config
key: deps-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
  deps-

Common mistakes

  • Keying on something that always changes (a commit SHA) → 0% hit rate.
  • Keying on something too stable → stale dependencies served forever.
  • Caching a directory that is rebuilt anyway, so the cache never helps.
  • Ignoring cache size limits and silently evicting hot caches.

Key takeaways

  • Cache the expensive, rarely-changing work: dependencies, build outputs, Docker layers.
  • Key on a lockfile hash; use restore-keys as a fallback prefix.
  • A wrong key either serves stale data or never hits - both look like "caching does nothing".

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →