Cache vs Workspaces vs Artifacts: Which One to Use for What

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_cache
  • persist_to_workspace / attach_workspace
  • store_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_artifacts does 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- to v2-) 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 of paths:).
  • 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}/artifacts API.
  • 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 to store_artifacts if you also want the raw report downloadable.

Additional Resources

Was this article helpful?
0 out of 0 found this helpful

Comments

0 comments

Article is closed for comments.