Cache and artifacts
Table of contents
- Difference between cache and artifacts
- Using the cache
- Using artifacts
- Advanced strategies
- Optimization
- Practical exercises
1 - Difference between cache and artifacts
Comparison
| Aspect | Cache | Artifacts |
|---|---|---|
| Purpose | Speed up builds | Share results |
| Persistence | Temporary (~7 days) | Configurable (1-90 days) |
| Scope | Same workflow/branch | Between jobs/workflows |
| Restoration | By key (hash) | By name |
| Max size | 10 GB total | 500 MB per artifact |
Use cases
🔝 Back to table of contents
2 - Using the cache
actions/cache
- uses: actions/cache@v4
with:
path: |
~/.npm
node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
Parameters
| Parameter | Description |
|---|---|
path | Paths to cache |
key | Unique key for this cache |
restore-keys | Fallback keys |
Node.js cache
# Méthode 1: actions/cache
- uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
- run: npm ci
# Méthode 2: Intégré dans setup-node (recommandé)
- uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- run: npm ci
Python cache
- uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
- run: pip install -r requirements.txt
# Ou manuellement
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
Docker cache
- uses: docker/build-push-action@v5
with:
context: .
push: true
tags: user/app:latest
cache-from: type=gha
cache-to: type=gha,mode=max
Check the cache hit
- uses: actions/cache@v4
id: cache
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
- name: Install if no cache
if: steps.cache.outputs.cache-hit != 'true'
run: npm ci
🔝 Back to table of contents
3 - Using artifacts
Upload artifact
- uses: actions/upload-artifact@v4
with:
name: my-artifact # Nom de l'artifact
path: | # Fichiers/dossiers
dist/
build/output.zip
retention-days: 5 # Durée de rétention
if-no-files-found: error # error, warn, ignore
Download artifact
- uses: actions/download-artifact@v4
with:
name: my-artifact
path: ./downloaded # Destination
Share between jobs
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
test:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: build-output
path: ./dist
- run: npm test
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: build-output
path: ./dist
- run: ./deploy.sh
Multiple artifacts
# Upload plusieurs artifacts
- uses: actions/upload-artifact@v4
with:
name: test-report
path: test-results/
- uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage/
# Download tous les artifacts
- uses: actions/download-artifact@v4
# Sans 'name', télécharge tous les artifacts
🔝 Back to table of contents
4 - Advanced strategies
Smart cache keys
# Clé avec version + lock file
key: v1-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
# Inclure la version de Node
key: ${{ runner.os }}-node${{ matrix.node }}-${{ hashFiles('**/package-lock.json') }}
# Fallback progressif
restore-keys: |
${{ runner.os }}-node${{ matrix.node }}-
${{ runner.os }}-node-
${{ runner.os }}-
Conditional cache
- uses: actions/cache@v4
if: github.event_name == 'push'
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
Artifacts with a pattern
- uses: actions/upload-artifact@v4
with:
name: logs
path: |
**/*.log
!**/node_modules/**
Compress artifacts
- name: Compress before upload
run: tar -czf build.tar.gz dist/
- uses: actions/upload-artifact@v4
with:
name: build
path: build.tar.gz
🔝 Back to table of contents
5 - Optimization
Measure the impact
- name: Build without cache
run: |
START=$(date +%s)
npm ci
END=$(date +%s)
echo "Install time: $((END-START))s"
Cache best practices
# ✅ Bon : Hash du lockfile
key: npm-${{ hashFiles('**/package-lock.json') }}
# ✅ Bon : Inclure OS et version
key: ${{ runner.os }}-node18-${{ hashFiles('**/package-lock.json') }}
# ❌ Mauvais : Clé statique
key: npm-dependencies
# ❌ Mauvais : Hash trop large
key: ${{ hashFiles('**/*') }}
Limits to know
| Limit | Value |
|---|---|
| Total cache per repo | 10 GB |
| Cache retention | 7 days (inactive) |
| Artifact max size | 500 MB |
| Artifact retention | 1-90 days |
Clean up the caches
# Via GitHub CLI
gh cache list
gh cache delete KEY
🔝 Back to table of contents
6 - Practical exercises
Exercise 1: npm cache
Create a workflow with npm cache:
Solution
name: Build with Cache
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- run: npm ci
- run: npm run build
Exercise 2: Share build between jobs
Share the build output with the deployment job:
Solution
name: Build and Deploy
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: ./dist
- run: ls -la dist/
Quiz
Q1. What is the default cache retention period?
Answer
7 days of inactivity.
Q2. How do you check whether the cache was restored?
Answer
steps.cache.outputs.cache-hit == 'true'
🔝 Back to table of contents
Key takeaways
- Cache: speeds up builds (dependencies)
- Artifacts: share results between jobs
hashFiles()for unique cache keysrestore-keysfor progressive fallback- setup-node/python: built-in cache
- 10 GB cache limit per repo
- Artifacts downloadable from the GitHub UI