How do I cache node_modules / npm in GitHub Actions?
CI installs deps from scratch every run. Slow. What is the current best pattern?
github-actionscachenpm
CI installs deps from scratch every run. Slow. What is the current best pattern?
Accepted solution
Prefer `actions/setup-node`'s built-in cache — it caches the npm/yarn/pnpm store and keys on your lockfile automatically.
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ciIf you need to cache `node_modules` itself (monorepos, postinstall-heavy installs) do it explicitly and key on the lockfile hash:
- uses: actions/cache@v4
with:
path: node_modules
key: ${{ runner.os }}-node20-${{ hashFiles('**/package-lock.json') }}Two warnings: include the OS and Node version in the key or you will restore Linux binaries onto a Windows runner and get cryptic native-module errors. And never use a loose `restore-keys` fallback with `node_modules` — a partially stale tree is worse than a clean `npm ci`, which typically only costs 20–40 seconds with the store cached.