Coockar

Published: 1 min read

Faster CI builds with layered caches and lockfile discipline

Dependency installation dominated our CI time, so I rebuilt the pipeline around a lockfile-keyed cache. Before-and-after numbers included.

A static site’s CI has three layers: installing dependencies, building the site, and verifying the result. Timing them showed dependency installation taking one minute forty seconds of a two-and-a-half-minute run. Caching that single layer is where the payoff concentrates.

Designing the cache key

The cache is keyed on the lockfile hash. As long as the lockfile is unchanged the dependency tree is identical, so a wholesale restore is safe.

  • Key: deps-${{ hashFiles('package-lock.json') }}
  • Restore target: the package manager’s store directory
  • A full install runs only when the lockfile changes, replacing the cache

Caching node_modules directly is a scheme that had broken for me before when the OS or toolchain moved; restoring through the store keeps the integrity checks in play.

Measured result

After the change, dependency installation went from 1m40s to 12 seconds, and the whole CI run from about 2m30s to just under a minute. Caching build artifacts themselves (optimized images and the like) has a hit rate that is hard to predict, so it stays deferred as the next step.

Takeaway

The fast route to a fast CI is to measure the slowest layer first and touch only that layer. Cache everything at once and you lose the ability to tell what broke when something does.