Speeding Up Your GitHub Actions with Cache
We all love GitHub workflows, but I loved it even more when I learned how to use the GitHub Actions cache.
GitHub Actions caching can save your day. I’ll explain it in a simple way: how it works, why it’s important, and how you can speed up your pipelines without being a DevOps expert.
The common problem
Here’s what most of us do in a typical GitHub Actions setup:
steps:
- uses: actions/checkout@v4
- name: Install Node.js dependencies
run: npm install
- name: Build the app
run: npm run build
Pretty normal, right?
But the problem is:
- Every single run → npm install from scratch.
- Build everything from zero.
- No reuse, no speed boost.
Result?
⏳ Slow builds.
💸 More wasted CI minutes.
Why Cache Exists (and Why You Should Care)
Caching is basically remembering stuff between runs.
If your dependencies didn’t change, why reinstall them?
If your build artifacts didn’t change, why rebuild everything?
With cache you can:
- Skip unnecessary work.
- Cut your workflow time in half (sometimes even more).
- Save money if you pay for extra minutes.
- Make your CI feel fast again.
Let’s Cache Your Node.js Stuff
The easiest win is caching your node_modules or pnpm store.
Here’s a basic example:
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
- name: Cache Node.js dependencies
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install dependencies
run: npm ci
- name: Build the app
run: npm run build
What’s happening here?
- path → What we’re caching (
~/.npm, or~/.pnpm-store/v3for pnpm). - key → A unique ID based on your
package-lock.json. - restore-keys → If the exact cache isn’t found, GitHub tries to grab a similar one.
✅ If you didn’t change your dependencies → instant install.
✅ If you did → it falls back to a fresh install.
Bonus Tip: Cache Your Build Artifacts Too
Got a heavy build like Next.js or Vite?
You can cache the output too:
- name: Cache build artifacts
uses: actions/cache@v4
with:
path: |
.next/cache
dist
key: ${{ runner.os }}-build-${{ github.sha }}
restore-keys: |
${{ runner.os }}-build-
This way you save your .next/cache or dist/ folders between runs.
Common Mistakes (and How Not to Suffer)
| Mistake | How to avoid it |
|---|---|
| Cache always misses | Make sure your cache key is based on a stable file like package-lock.json, not random stuff. |
| Cache too big | GitHub limits individual caches to 400MB. Split them if needed. |
| Broken cache breaks builds | Always use restore-keys as fallback. |
| Wrong paths | Cache your npm or pnpm store, not random folders like node_modules directly. |
Real-World Example: React + pnpm
If you’re using pnpm, setup-node has built-in caching now. Even easier:
name: Build and Deploy
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: "pnpm" # 🔥 automatic caching!
- name: Install dependencies
run: pnpm install
- name: Build the app
run: pnpm run build
👉 No need to even set up actions/cache manually for pnpm/yarn/npm anymore.
GitHub’s smart enough to handle it for you.
Pro Tips
- Use native caching if possible (
setup-node,setup-python, etc.). - Clear broken caches manually in the GitHub UI if stuff gets weird.
- Don’t cache everything — just expensive things like dependencies or heavy build outputs.
- Watch your cache size — GitHub has limits!
Wrapping Up
Caching in GitHub Actions is one of the easiest hacks to make your pipelines feel fast and efficient.
Less waiting, more coding. 🚀
If you haven’t added cache yet, you’re seriously missing out.
For deeper details, check out the actions/cache docs.
⚡ Bonus Tip
You can literally save minutes per build just by caching smart.
Want proof? Here’s a real before/after I saw:
| Before Cache | After Cache | |
|---|---|---|
| Install Dependencies | 1 min 47 sec | 11 sec |
| Build App | 2 min 25 sec | 50 sec |
Worth it, right? 🚀