How to Choose Between Caching node_modules and the Package Manager Store
Cache the package manager download store and run a clean install; caching node_modules directly risks stale or platform-specific binaries.
The download store (~/.npm, the yarn cache, the pnpm store) holds tarballs that are portable and reused by a clean install. node_modules holds compiled, resolved output that can break when the runner OS or Node version changes, so most workflows cache the store and let npm ci rebuild.
Steps
- Prefer caching the store path for your package manager.
- Key on
runner.osplus the lockfile hash so native builds stay valid. - Run
npm ci(or the equivalent) rather than restoring node_modules wholesale.
Store paths
Terminal
# npm -> ~/.npm
# yarn v1 -> $(yarn cache dir)
# pnpm -> $(pnpm store path)Workflow
.github/workflows/ci.yml
steps:
- uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
- run: npm ciGotchas
- A node_modules cache built on one OS can carry native addons that segfault on another.
- If you must cache node_modules, include the Node version in the key.
Related guides
How to Use the Built-in cache Input of setup-nodeEnable dependency caching with one line using the cache input of actions/setup-node, which auto-detects your…
How to Set a Cache Key and restore-keys in GitHub ActionsConfigure actions/cache with an exact key and a restore-keys fallback list so a lockfile change still restore…