Skip to main content
In this lesson, we’ll explore how to speed up GitHub Actions workflows by caching Node.js dependencies across jobs. Caching reduces redundant installs, lowers CI time, and saves costs.

Why Cache Dependencies? Workflow Performance without Caching

Without caching, each job installs dependencies from scratch, adding significant overhead. For example, our previous workflow (~59 s total):
The image shows a GitHub Actions workflow summary for a project, indicating successful completion of unit testing and code coverage jobs across different environments.
Inspecting the macOS unit test job:
  • Setup Node.js: ~20 s
  • npm install: ~15 s
Especially in larger projects, fresh installs significantly inflate build times. Caching is the solution.

How Caching Works in GitHub Actions

GitHub Actions provides the actions/cache action to store and restore files between workflow runs.
  • key: Unique cache identifier (often includes OS & file hash).
  • path: Directories or files to cache.
The action checks for a cache hit; on miss, it runs normally and stores the cache for future runs.
The image shows a GitHub Docs page about caching dependencies to speed up workflows, with a sidebar menu and article sections listed.
Use a strong cache key (e.g., ${{ runner.os }}-deps-${{ hashFiles('package-lock.json') }}) to invalidate the cache automatically when dependencies change.

Prerequisites and Inputs

Ensure you have:
  • A lockfile (package-lock.json or yarn.lock) at the repo root.
  • actions/cache@v3 available in your workflow.
The image shows a section of a GitHub README file detailing prerequisites and inputs for setting up a workflow, including information on cache keys, paths, and environment variables.
A minimal cache example:

Implementing Caching in Your Workflow

Add cache steps before npm install in both unit-testing and code-coverage jobs. We use ${{ runner.os }}-node-modules-${{ hashFiles('package-lock.json') }} as the key.

Unit Testing Job with Cache

  • path: node_modules directory.
  • key: Includes OS and lockfile hash for automatic invalidation.

Code Coverage Job with Cache

Commit and push to trigger the workflow.

Verifying Cache Effectiveness

On the first run, cache miss:
The image shows a GitHub Actions workflow interface with a successful unit testing job for an Ubuntu environment, including steps like caching NPM dependencies.
After completion, caches appear in the repository settings:
The image shows a GitHub Actions page displaying cache details for a project, with entries for macOS and Linux node modules. Each cache entry includes size, caching time, and branch information.
On the second run, cache hit reduces npm install to ~1 s:

Next Steps: Invalidate Cache on Dependency Changes

To test cache invalidation, update your package.json dependencies and re-run the workflow. The hash changes, creating a fresh cache.
Avoid overly broad cache paths to prevent storing unwanted files. Restrict the path to necessary directories only.

Watch Video