This article explains the difference between cache, workspaces, and artifacts on CircleCI, and how to pick the right one for a given file-sharing need.
You need to move files from one place to another in a CircleCI pipeline. That could mean between steps in the same job, between two jobs in the same workflow, or out of the build so you (or another reviewer) can download them later. CircleCI exposes three features that look similar:
save_cache/restore_cachepersist_to_workspace/attach_workspacestore_artifacts
How they differ
| Feature | Lives where | Scoped to | Lifetime | Best for |
|---|---|---|---|---|
| Cache | CircleCI-managed object storage, keyed by your key: expression |
The project (shared across branches within the project) | 15 days by default (also the maximum), configurable in Plan > Usage Controls |
Speeding up future jobs by reusing expensive-to-rebuild content (your package manager's dependency directory, downloaded SDKs, prebuilt toolchains) |
| Workspace | CircleCI-managed object storage, attached to one workflow run | The current workflow only | 15 days by default (also the maximum), configurable in Plan > Usage Controls. Persists beyond the workflow so you can rerun failed jobs; does not carry over to a new pipeline run on a new commit. |
Passing files between jobs in the same workflow (compiled binaries, generated configs, files produced by an earlier job) |
| Artifact | CircleCI-managed object storage, downloadable from the job's web UI / API | The job (browsable from the Job page or API) | 30 days by default (also the maximum), configurable in Plan > Usage Controls |
Making build output available for download by you or external tools (test reports, screenshots, coverage reports, release binaries) |
Common wrong-tool failure modes:
- Using a cache to pass build output between jobs: works on a warm cache, silently breaks the first time the cache misses (key change, lockfile change, or 15-day expiry).
- Using a workspace to share dependencies across pipelines: works for one run, then re-installs from scratch on the next pipeline because workspaces are per workflow run.
- Using an artifact to feed a downstream job:
store_artifactsdoes not have a "restore" step, so downstream jobs cannot directly read artifacts the way they read workspaces.
Use a cache when
The content is expensive to produce, and you want to skip producing it on future pipeline runs as long as the inputs have not changed.
- restore_cache:
keys:
- v1-deps-{{ checksum "<your-lockfile>" }}
- v1-deps-
- run: <install dependencies>
- save_cache:
key: v1-deps-{{ checksum "<your-lockfile>" }}
paths:
- <dependency cache directory>Key tips:
- Include a hash of the lockfile in the key so a dependency change invalidates the cache.
- Add a fallback prefix key (
v1-deps-) so partial cache hits are still useful. - Caches are immutable. Once written under a key, they are not overwritten. Bump the version prefix (
v1-tov2-) when you want to invalidate explicitly. - Caches expire 15 days after creation (the default and current maximum). Restoring a cache does not reset that timer.
Use a workspace when
You need to share files between jobs in the same workflow. Typical pattern: a build job produces a binary, a test job consumes it, a deploy job uploads it.
jobs:
build:
steps:
- checkout
- run: <build command>
- persist_to_workspace:
root: .
paths:
- <build output directory>/
test:
steps:
- attach_workspace:
at: .
- run: <test command>
workflows:
build-and-test:
jobs:
- build
- test:
requires: [build]Key tips:
root:is the directory you persist from (the parent ofpaths:).at:is the directory you attach to in the downstream job.- Workspaces are per workflow run. Each new pipeline gets a fresh, empty workspace.
- Workspace data is retained for 15 days by default (the maximum), so a rerun of a failed workflow can still attach the original workspace.
Use an artifact when
You want to download the file (or have an external system download it) after the job finishes. Test reports, generated docs, screenshots from a failed UI test, signed release binaries, coverage reports.
- run: <command that produces a report or file>
- store_artifacts:
path: <path to the file or directory>
destination: <prefix shown in the Artifacts tab>Key tips:
- Artifacts are visible on the job's web page under the Artifacts tab and via the
GET /project/{slug}/{job-num}/artifactsAPI. - Artifacts are not a way to pass files to a downstream job in the same workflow. Use a workspace for that.
- For test results that should populate the Tests tab and the Insights flaky-test page, use
store_test_results(which expects JUnit XML), in addition tostore_artifactsif you also want the raw report downloadable.
Comments
Article is closed for comments.