Skip to content
Latchkey

How to Cache npm Dependencies in GitHub Actions

Cache ~/.npm, key it on the package-lock.json hash, and npm ci reuses the download cache instead of refetching every package.

The right thing to cache for npm is ~/.npm (the install download cache), not node_modules. Key it on a hash of package-lock.json so the entry rotates only when dependencies change, and add a restore-keys prefix for partial hits.

Steps

  • Cache the ~/.npm directory, not node_modules.
  • Key the cache on hashFiles('**/package-lock.json').
  • Add a npm- prefix under restore-keys for a warm start on lockfile changes.
  • Run npm ci after the restore step.

Workflow

.github/workflows/ci.yml
steps:
  - uses: actions/checkout@v4
  - uses: actions/cache@v4
    with:
      path: ~/.npm
      key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
      restore-keys: |
        npm-${{ runner.os }}-
  - run: npm ci

Gotchas

  • The built-in cache: npm input of actions/setup-node does the same thing with less YAML; reach for actions/cache when you need a custom key.
  • Including runner.os in the key avoids restoring a Linux cache onto a Windows runner.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →