Skip to main content

Cache and artifacts


Table of contents

  1. Difference between cache and artifacts
  2. Using the cache
  3. Using artifacts
  4. Advanced strategies
  5. Optimization
  6. Practical exercises


1 - Difference between cache and artifacts

Comparison

AspectCacheArtifacts
PurposeSpeed up buildsShare results
PersistenceTemporary (~7 days)Configurable (1-90 days)
ScopeSame workflow/branchBetween jobs/workflows
RestorationBy key (hash)By name
Max size10 GB total500 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

ParameterDescription
pathPaths to cache
keyUnique key for this cache
restore-keysFallback 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

LimitValue
Total cache per repo10 GB
Cache retention7 days (inactive)
Artifact max size500 MB
Artifact retention1-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 keys
  • restore-keys for progressive fallback
  • setup-node/python: built-in cache
  • 10 GB cache limit per repo
  • Artifacts downloadable from the GitHub UI

🔝 Back to table of contents


← Previous chapter | Next chapter: Matrix builds →