Skip to content
Latchkey

How to Avoid Re-Downloading Dependencies in CI

Re-downloading the same packages on every cold runner is the most common avoidable CI cost. Caching the store fixes it across ecosystems.

The pattern is the same in every language: a cold runner fetches every dependency from a registry. Caching the package store keyed on the lockfile, then installing offline, eliminates the repeat download.

1. Cache the package store, keyed on the lockfile

Cache the ecosystem store (not the project tree) keyed on the lockfile so an unchanged dependency set restores instead of re-downloading.

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

2. Install offline against the cache

Prefer the offline path so a warm cache never hits the network.

.github/workflows/ci.yml
- run: npm ci --prefer-offline --no-audit

3. Proxy the registry for big or private deps

When you cannot cache everything (large binaries, private registries), a pull-through registry proxy keeps a local copy so the second fetch is local. This complements, not replaces, the store cache.

4. Keep deps warm on the runner

Latchkey managed runners can keep common dependency stores warm on the image, so the most-used packages are already present and even the cache restore is skipped.

Key takeaways

  • Cache the ecosystem store keyed on the lockfile, across every language.
  • Install offline so a warm cache never touches the network.
  • Use a registry proxy for deps too large or private to cache directly.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →