CodeOath
← All posts
CI/CD & DevOps60 min total · 17 parts

CI/CD Pipelines Explained: From git push to Production

Contents — Part 8 of 17: Caching Dependencies
Part 8 of 17 · ~1 min

Caching Dependencies

Reinstalling every dependency from scratch on every single run is one of the largest and most avoidable sources of slow CI. Most platforms support caching a directory keyed by a hash of whatever determines its contents:

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

The key here changes exactly when package-lock.json changes — as long as dependencies haven't changed, the cache hits and npm ci restores from the cached download cache instead of fetching everything over the network again. restore-keys provides a fallback: if there's no exact match for the current lockfile hash (a new dependency was just added), it can still restore the most recent cache with a matching prefix and only need to fetch the new packages, rather than starting from nothing.

This is exactly analogous to Docker's layer caching (see Docker Fundamentals) — both are "skip the work if the relevant input hasn't changed" applied to a different stage of the pipeline, and both share the same failure mode: a cache key that's too broad (doesn't change when it should) serves stale results, while one that's too narrow (changes when it shouldn't) never actually hits.