Skip to content
Latchkey

Caching Dependencies to Speed Up Runs: A Tutorial

Re-downloading the same dependencies on every run is wasted time and money; caching reuses them instead.

Installing dependencies from scratch on every CI run is one of the biggest time sinks in a pipeline. Caching lets you reuse them between runs, often cutting minutes off each build. This tutorial explains how caching works and how to set it up correctly.

Why caching matters

Every job starts on a clean runner, so by default it re-downloads and rebuilds all dependencies every time. For a large project that can be the slowest part of the run. Since most CI providers bill per minute, slow installs cost real money on top of slowing down feedback. Caching reuses the heavy, rarely-changing dependency directory across runs.

How the cache key works

The actions/cache action saves a directory under a key. On the next run, if the key matches, you get a *cache hit* and the directory is restored; if not, a *cache miss* and the cache is rebuilt and saved. The key should change only when your dependencies change - so it is typically built from a hash of your lockfile.

.github/workflows/ci.yml
steps:
  - uses: actions/checkout@v4
  - uses: actions/cache@v4
    with:
      path: ~/.npm
      key: npm-${{ hashFiles('package-lock.json') }}
      restore-keys: |
        npm-
  - run: npm ci

restore-keys as a fallback

The restore-keys list provides partial-match fallbacks. If the exact key misses, GitHub looks for the most recent cache whose key starts with a restore-key prefix. This means a small dependency change still restores *most* of the previous cache instead of starting from zero - a big speedup even on a miss.

Caching best practices

  • Key on your lockfile hash so the cache invalidates exactly when dependencies change.
  • Prefer the built-in cache: option in setup-* actions when available - it wires this up for you.
  • Cache the dependency download/store directory, not node_modules, when the package manager supports it.
  • On managed runner platforms like Latchkey, faster runners plus caching compound to lower per-run cost.

Key takeaways

  • Caching reuses heavy dependency directories across runs to save time and cost.
  • The cache key (usually a lockfile hash) controls hits and misses; restore-keys add fallbacks.
  • Prefer the built-in cache: option in setup actions when it exists.

Related guides

See what you would save - Latchkey managed runners with self-healing. Start free →