Modern QA2026Caching — tiles
Log inJoin
27 / 48 · 16 CI/CD Pipelines · Pipeline Optimization← prev⊞ allnext →☰ Read as one page

5.2Caching

Caching is the single most impactful optimization. Without caching, every pipeline run downloads and installs dependencies from scratch -- often taking 2-5 minutes that add zero value.

What to Cache

What Cache Key Typical Savings
Node modules package-lock.json hash 1-3 minutes
Python virtualenvs requirements.txt or poetry.lock hash 1-2 minutes
Playwright browsers package-lock.json hash 2-4 minutes
Docker layers Dockerfile hash 2-10 minutes
Gradle/Maven dependencies build.gradle or pom.xml hash 1-5 minutes
Go modules go.sum hash 30s-2 minutes

GitHub Actions Caching

# Cache node_modules (automatic with setup-node)
- uses: actions/setup-node@v4
  with:
    node-version: 24
    cache: 'npm'

# Cache Playwright browsers (manual)
- uses: actions/cache@v4
  id: playwright-cache
  with:
    path: ~/.cache/ms-playwright
    key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}

- run: npx playwright install --with-deps
  if: steps.playwright-cache.outputs.cache-hit != 'true'

The cache-hit output lets you skip installation entirely when the cache is valid. This turns a 3-minute Playwright browser installation into a 5-second cache restore.

Cache Invalidation Strategy

Cache keys should change when dependencies change and remain stable otherwise:

# Good: Changes only when lockfile changes
key: deps-${{ hashFiles('package-lock.json') }}

# Bad: Changes on every commit (cache is never used)
key: deps-${{ github.sha }}

# Better: Fallback to partial cache match
key: deps-${{ hashFiles('package-lock.json') }}
restore-keys: |
  deps-

The restore-keys fallback finds the most recent cache that starts with deps-, which may be slightly stale but is much faster than installing from scratch.