GitHub Actions Certification
Continuous Integration with GitHub Actions
Invalidate Cache
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
:
{
"name": "Solar_System",
"version": "6.6.7",
"author": "Siddharth Barahalikar <[email protected]>",
"homepage": "https://www.linkedin.com/in/barahalikar-siddharth/",
"license": "MIT",
"scripts": {
"start": "node app.js",
"test": "mocha app-test.js --timeout 10000 --reporter mocha-junit-reporter --exit",
"coverage": "nyc --reporter cobertura --reporter lcov --reporter text --reporter json-summary mocha app-test.js --timeout 10000"
},
"nyc": {
"check-coverage": true,
"lines": 90
},
"dependencies": {
"cors": "^2.8.5",
"express": "^4.18.2",
"mocha-junit-reporter": "2.2.1",
"mongoose": "5.13.20",
"nyc": "^15.1.0"
},
"devDependencies": {
"chai": "*",
"chai-http": "*",
"mocha": "*"
}
}
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:
# 1. Update your feature branch
git pull
# 2. Install nodemon and update lockfile
npm install nodemon --save
# 3. Review changes
git diff package.json package-lock.json
# 4. Commit and push
git add package.json package-lock.json
git commit -m "Add nodemon dependency"
git push
After this, your package.json
dependencies look like:
{
"dependencies": {
"cors": "^2.8.5",
"express": "^4.18.2",
"mocha-junit-reporter": "2.2.1",
"mongoose": "5.13.20",
"nodemon": "^3.0.1",
"nyc": "^15.1.0"
}
}
And package-lock.json
is updated, producing a new hash.
Note
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
:
Step | Action | Description |
---|---|---|
Setup Node.js | uses: actions/setup-node@v3 | Installs Node.js for the specified version. |
Cache NPM dependencies | uses: actions/cache@v3 | Caches node_modules keyed by the lockfile’s hash. |
Install Dependencies | run: npm install | Restores or installs NPM packages. |
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.nodejs_version }}
- name: Cache NPM dependencies
uses: actions/cache@v3
with:
path: node_modules
key: ${{ runner.os }}-node-modules-${{ hashFiles('package-lock.json') }}
- name: Install Dependencies
run: npm install
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:
- Cache NPM dependencies: No existing cache matches the new key, so the step falls back to installing from npm.
- Install Dependencies:
npm install
populatesnode_modules
. - Upload Cache: One job uploads the newly generated cache.
- Parallel Jobs: Other jobs may see “Failed to save cache” if they attempt an upload after the first; this is expected.
Warning
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:
Cache not found for input key, proceeding to npm install...
or
Uploading cache...
/usr/bin/tar --posix -cf cache.tzst --exclude cache.tzst -P -C /home/runner/work/solar-system/solar-system --files-from manifest.txt --use-compress-program=zstdmt
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:
Conclusion
By hashing package-lock.json
in your cache key:
- Each dependency update generates a new hash.
- The cache restore step misses on outdated keys.
- Dependencies are installed from scratch.
- A fresh cache is uploaded for subsequent runs.
Links and References
Watch Video
Watch video content