How to Cache Dependencies in GitHub Actions
In this tutorial, you'll learn about How to Cache Dependencies in GitHub Actions. We cover key concepts, practical examples, and best practices.
The Problem
Your GitHub Actions workflow installs dependencies from scratch on every run, taking several minutes per build. Caching restores previously downloaded packages so subsequent runs complete faster.
Quick Fix
Step 1: Cache npm dependencies
- name: Cache npm dependencies
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
The key is derived from the lockfile hash. When the lockfile changes, the cache is invalidated and a new one is created.
Step 2: Cache pip dependencies
- name: Cache pip dependencies
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
Step 3: Cache Maven dependencies
- name: Cache Maven dependencies
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
Step 4: Full workflow with caching
name: CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Cache npm
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
Step 5: Cache multiple paths in one step
- name: Cache multiple paths
uses: actions/cache@v4
with:
path: |
~/.npm
~/.cache/pip
~/.m2/repository
key: ${{ runner.os }}-combined-${{ hashFiles('**/package-lock.json', '**/requirements.txt', '**/pom.xml') }}
Step 6: Verify cache hit/miss
In the workflow output, look for:
Cache restored from cache for key: linux-npm-abc123...
Cache miss for key: linux-npm-abc123...
Step 7: Set cache size limit
- name: Cache with size limit
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
max-size: 200MB
Alternative Solutions
Use language-specific caching actions like actions/setup-node with cache: npm which handles caching automatically:
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
Common Errors
Cache quota exceeded: GitHub allows 10 GB of cache per repository. Monitor usage under Settings > Actions > Caches and prune old caches with gh actions cache delete.
Cache never hits: If hashFiles includes files that change on every commit (like timestamps or build IDs), the cache is invalidated every run. Only hash files that change between dependency updates.
Cache save fails silently: If the cache step fails, the workflow continues but without caching. Check the step output for "Cache saved successfully" or error messages.
Cross-branch cache pollution: Without branch-specific keys, a cache from one branch may be restored on another. Include github.ref in the cache key to isolate by branch.
Prevention
- Use lockfiles (
package-lock.json,requirements.txt) in the cache key for automatic invalidation. - Set a
max-sizelimit to avoid filling the GitHub cache quota (10 GB per repo). - Use
restore-keysas a fallback when the exact key misses. - Monitor the Actions cache usage under Settings > Actions > Caches.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro