Jobs share nothing by default, so artifacts and caches are how pipelines move files and save minutes.
Artifacts are files a job produces that GitLab stores: artifacts: paths: lists them and expire_in sets how long they're kept. By default, jobs in later stages download the artifacts of all jobs in earlier stages; dependencies: or needs: restrict that. Artifacts can be browsed and downloaded in the UI.
artifacts:reports are special artifacts GitLab understands: junit test results show in merge requests, and there are report types for coverage, code quality and security scanners. Use when: always so reports upload even when tests fail.
A cache stores dependencies between pipelines to avoid re-downloading them. It lives on the runner (or in shared object storage), is best-effort, and is never guaranteed to exist. Configure cache: key: and paths:; key: files: [package-lock.json] changes the key whenever the lockfile changes. policy: pull on jobs that only read the cache avoids slow uploads.
The rule: artifacts are for passing results between jobs and to people; cache is for speeding things up. Never rely on a cache for correctness. Package managers should point their download directory inside the project (for example PIP_CACHE_DIR: $CI_PROJECT_DIR/.cache/pip), because only paths inside $CI_PROJECT_DIR can be cached or archived.
Example
variables:
PIP_CACHE_DIR: $CI_PROJECT_DIR/.cache/pip
test:
image: python:3.13
cache:
key:
files: [requirements.txt] # new cache when deps change
paths: [.cache/pip]
script:
- pip install -r requirements.txt
- pytest --junitxml=report.xml
artifacts:
when: always # upload even if tests fail
reports:
junit: report.xml # shown in the merge request
build:
stage: build
script: [make dist]
artifacts:
paths: [dist/]
expire_in: 1 weekRemember
- Artifacts = outputs for later jobs and humans; cache = speed-up only
- Key caches on lockfiles with cache:key:files
- Only paths inside $CI_PROJECT_DIR can be cached or archived
Watch out for
- Using cache to pass build output to a deploy job; the cache may be missing on another runner.