BlogCI/CD
Speed up GitHub Actions with dependency caching
Cache node_modules, pip wheels, and Go modules keyed on your lockfile hash, and warm the cache on main to cut minutes off every GitHub Actions run.
If every GitHub Actions run reinstalls dependencies from scratch, you are paying for the same download on every push. The actions/cache action stores a directory keyed on your lockfile and restores it next run — a one-line change that often halves wall-clock time.
cold run:npm ci ............ 1m48swarm cache:npm ci ............ 12s (cache hit)Key the cache on your lockfile
The key decides when the cache is reused. Hash the lockfile so it invalidates the moment dependencies change, and add a restore-keys fallback so a near-miss still restores most of it.
.github/workflows/ci.yml
- uses: actions/cache@v4with:path: ~/.npmkey: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}restore-keys: |npm-${{ runner.os }}-
Cache the download dir, not node_modules
Caching ~/.npm (or the pip / Go module cache) is safer than caching node_modules — you still run a real install, so postinstall scripts and platform binaries stay correct.
The setup actions already do this
For common languages you do not even need the cache action — the setup-* actions have it built in.
.github/workflows/ci.yml
- uses: actions/setup-node@v4with:node-version: 20cache: npm # restores + saves ~/.npm automatically
Caches are scoped and trusted
A cache written on a branch can be restored by PRs from it. Never cache secrets or build outputs you then trust implicitly — treat cache contents as untrusted input.