Skip to content
Français
CI/CD & Automatisation medium

Artifacts vs Cache: making the right choice

25 min de lecture

Read this page in French

Your CI workflow takes 8 minutes. On every run, it downloads the same dependencies, rebuilds the same files. Why start from scratch when nothing has changed?

GitHub Actions offers two mechanisms to avoid that waste: the cache and artifacts. They look similar, but they serve very different purposes. Choosing the right mechanism at the right moment can halve the duration of your workflows.

What you will learn

  • Tell the cache and the artifacts apart in one sentence
  • Pick the right mechanism for your need
  • Spot the two classic mistakes that come from confusing them
  • Combine cache and artifacts in a single workflow

The difference in one sentence

Cache and artifacts answer two distinct needs. The golden rule holds in two lines, keep it in mind, it settles most cases.

The golden rule

  • Cache = reusing files between runs (same workflow, different runs)
  • Artifacts = sharing files between jobs (same run, different jobs)

A quick comparison

This table puts the two mechanisms face to face on the criteria that matter when choosing: scope, lifetime, visibility and use cases.

AspectCacheArtifacts
PurposeSpeed up repeated buildsShare results
ScopeBetween runs (a repeated workflow)Between jobs (the same run)
Lifetime7 days without accessConfigurable (1-90 days)
Visible in the UINo (internal)Yes (downloadable)
Maximum size10 GB per repository (total)10 GB per artifact
Use casesnode_modules, .cache/pipBuilds, reports, binaries

The decision guide

Start from your goal: do you want to speed up an install, or move a result from one job to the next? Each one leads to a mechanism.

The common situations

Here are the concrete cases that come back the most often, sorted by the mechanism that suits them.

When to use the cache

  • Speeding up npm ci, pip install or mvn install
  • Reusing the dependencies between runs
  • Caching downloaded binaries (Terraform, kubectl and so on)
  • Speeding up incremental builds

Example: you push 3 consecutive commits, and the dependency cache is reused for all 3 runs.

When to use artifacts

  • Sharing the build between the test and deploy jobs
  • Keeping the test and coverage reports
  • Downloading the binaries from the GitHub interface
  • Keeping the debug logs when something fails

Example: a build job creates dist/, and the test and deploy jobs reuse it without rebuilding.

The mistakes to avoid

Two confusions keep coming back. Recognising them avoids workflows that are unstable or needlessly slow.

Using the cache to share between jobs

# ❌ DOES NOT WORK reliably
jobs:
build:
steps:
- run: npm run build
- uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: dist/
key: build-${{ github.sha }}
deploy:
needs: build
steps:
- uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
# Can fail! The cache is not guaranteed

Why? The cache is designed for runs, not for jobs.

Fix: use an artifact.

Using artifacts for the dependencies

# ❌ Wasteful: you upload node_modules on every run
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
path: node_modules/
# ✅ Use the cache
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
cache: 'npm'

Why? Dependencies are reusable between runs, so they belong in the cache.

The complete pattern: cache and artifacts

In a real workflow, you use both:

name: CI/CD
on:
push:
branches: [main]
# No rights by default: every job asks for the minimum
permissions: {}
jobs:
build:
runs-on: ubuntu-24.04
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# CACHE: speeding up npm ci
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run build
# ARTIFACT: sharing the build
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: dist
path: dist/
retention-days: 1
deploy:
needs: build
runs-on: ubuntu-24.04
permissions:
contents: read
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: dist
- run: ./deploy.sh

What happens:

  1. The cache speeds up npm ci (dependencies reused between runs)
  2. The artifact carries the build over to the deploy job
  3. You only build once

The "cache" half of that pattern then varies per ecosystem, each one having its own paths and its own traps: Python, Node.js and Java.

Key points

Cache = between runs

For the reusable files that speed up repeated builds.

Artifacts = between jobs

For the produced files you want to share or download.

The two complement each other

An optimised workflow uses the cache AND the artifacts.

Checklist:

  1. Dependencies go to the cache
  2. Build outputs go to artifacts
  3. Sharing between jobs means artifacts plus needs:
  4. Debug logs go to artifacts with if: failure()

Next steps

  • Runners: introduction: what the machine changes in that arbitration, a persistent disk making the local cache almost free.
  • Ephemeral runners: the edge case where the local cache does not exist, and where the artifact becomes the only possible transport again.
  • Isolating the runners: why a cache shared across levels of trust is a security problem, not only a performance one.

Is this site useful to you?

Fewer than 1% of readers support this site.

I maintain more than 700 free guides, with no ads and no tracking. Any support, even a symbolic one, helps cover hosting and keeps these resources free. Thank you for the help.

The form does not show? Open Ko-fi in a new tab.

Subscribe and follow my DevSecOps work on LinkedIn