Skip to main content
In this guide, you’ll learn how GitHub Actions uses a hash of package-lock.json to invalidate and refresh the NPM cache whenever dependencies change. By incorporating hashFiles('package-lock.json') into your cache key, you ensure that outdated artifacts aren’t reused and that a fresh cache is stored after updates.

Initial Cache Setup

Assume your repository includes a workflow that caches node_modules based on the lockfile’s hash. Here’s the original package.json:
These dependencies are restored from cache on each workflow run and only invalidated when package-lock.json changes.

Adding a New Dependency

When you introduce a new package, the lockfile hash changes, triggering a cache miss:
After this, your package.json dependencies look like:
And package-lock.json is updated, producing a new hash.
Using npm install --save updates both package.json and package-lock.json, ensuring the cache key changes automatically.

Workflow Configuration

Include these steps in your .github/workflows/ci.yml:
Because the cache key is based on hashFiles('package-lock.json'), any modification to your lockfile results in a cache miss.

Triggering the Workflow and Cache Invalidation

Once you push the updated lockfile:
  1. Cache NPM dependencies: No existing cache matches the new key, so the step falls back to installing from npm.
  2. Install Dependencies: npm install populates node_modules.
  3. Upload Cache: One job uploads the newly generated cache.
  4. Parallel Jobs: Other jobs may see “Failed to save cache” if they attempt an upload after the first; this is expected.
The image shows a GitHub Actions workflow interface for a project named "solar-system," displaying the status of unit testing jobs on different environments, with a focus on caching NPM dependencies.
In parallel builds, only the first job to upload the cache succeeds. Subsequent jobs will skip uploading the same key.

Inspecting Cache Behavior Across Jobs

During a run, you might see logs like:
or
The image shows a GitHub Actions workflow interface with a list of jobs, including unit testing and code coverage, indicating successful completion of tasks. The highlighted section is "Cache NPM dependencies" under a unit testing job.
This demonstrates how one job restores or saves the cache, while others detect it’s already stored and skip.

Viewing Saved Caches

You can review cache details in the GitHub Actions UI under the workflow run or by examining the tar logs. Example:
The image shows a GitHub Actions interface displaying cache details for a project, including cache names, sizes, and usage times.

Conclusion

By hashing package-lock.json in your cache key:
  1. Each dependency update generates a new hash.
  2. The cache restore step misses on outdated keys.
  3. Dependencies are installed from scratch.
  4. A fresh cache is uploaded for subsequent runs.

Watch Video