跪拜 Guibai
← All articles
Frontend · JavaScript · Programmer

CI Cache Audit: 46% of Dependency Installs in Top JS Repos Run Cacheless

By kyriewen ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Uncached dependency installs add minutes to every push and PR, and a missing cache-hit guard turns caching into pure overhead. The fix is not better cache-key syntax, which top repos already use; it's turning caching on and adding one if-condition before npm ci.

Summary

Sparse-checking the workflow directories of GitHub's 500 most-starred JS/TS repos reveals 2,032 workflows that install dependencies. 1,098 configure a cache; the remaining 934, 46%, never do. At the repo level, 107 of the 380 repos that install dependencies have never enabled caching once. The scan used regex rather than a YAML parser, so caching hidden inside composite actions or reusable workflows is invisible to it; every figure is a lower bound.

Writing cache keys correctly is already the norm. Of 362 hand-written actions/cache steps, 87.6% include a lockfile hash in the key. The gap is simply enabling caching. A separate waste mode is caching node_modules without guarding npm ci: 129 jobs cache node_modules, 65 also run npm ci, and 21 of those (across 7 repos) lack a cache-hit guard. npm ci deletes the restored node_modules and reinstalls from scratch, so the cache download, extract, and save all run for nothing.

The practical checks are a couple of greps plus one manual rule: never cache node_modules without an if: cache-hit condition before npm ci; otherwise cache the package manager's own directory. Small projects may not benefit; if an install takes under two seconds, restoring a cache can be slower than just installing.

Takeaways
— Of 500 top-starred JS/TS repos, 422 have workflow directories; 380 of those install dependencies, and 107 never configure a cache.
— 2,032 workflows install dependencies; 1,098 configure a cache and 934 (46%) configure none.
— 818 workflows use setup-node managed caching; 362 use actions/cache, and 87.6% of those include a lockfile hash in the key.
— 131 workflows explicitly disable caching via `package-manager-cache: false`; 46 repos have turbo/nx remote cache; 38 install inside docker build; 733 remain unjustified.
— 129 jobs cache node_modules; 65 also run npm ci; 21 of those (across 7 repos) lack a cache-hit guard, so npm ci deletes the restored cache.
— A grep for cache config across workflows: `grep -rn "actions/cache\|cache: npm\|cache: pnpm\|cache: yarn" .github/workflows`.
— Recommended: cache the package manager's own directory (~/.npm, ~/.cache/yarn, pnpm store) via setup-node's `cache:` option; caching node_modules requires a guard.
Conclusions

Cache-key correctness is a solved problem among top repos; the real failure mode is simply not enabling caching at all.

Caching node_modules without a cache-hit guard is worse than no caching: the restore gets deleted by npm ci, so the workflow pays download and save costs for zero benefit.

The regex-based scan makes every number a lower bound, meaning the real prevalence of cacheless CI is probably higher than measured.

Small projects can legitimately skip caching; under a two-second install, cache restore may be slower than a fresh install, so blanket recommendations to cache are wrong.

Concepts & terms
setup-node managed cache
GitHub Actions' setup-node `cache:` option automatically sets the cache key, path, and restore process for the package manager's cache directory, replacing a separate cache step.
cache-hit guard
An `if: steps.cache.outputs.cache-hit != 'true'` condition on `npm ci` that skips the install when the node_modules cache was restored.
restore-keys
A fallback in `actions/cache` that lets a new cache key still hit a previous run's cache entry, useful when keys contain commit IDs.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗