CI/CD·7 min read·

Artifacts, Caches, and Dependencies Across Stages

Move build outputs between pipeline stages correctly while keeping dependencies cached and artifacts immutable.

NB

Netbay Cloud Team

Netbay Engineering

On this page

A multi-stage pipeline has to pass things between its stages: the compiled artifact, cached dependencies, reports. Get these transfers wrong and stages drift apart, artifacts rot, and builds stop being reproducible. This post separates three concepts people conflate — artifacts, caches, and dependencies — and shows how to handle each correctly across stages.

The Three Concepts, Distinguished

  • **Dependencies** are the third-party libraries your build needs. They change rarely. Cache them between runs.
  • **Caches** are reusable intermediate data keyed by what produced them. They speed things up; they are not the build's output.
  • **Artifacts** are the actual outputs of a stage, the immutable thing you deploy or the reports you consume. They must be untouchable once produced.

Confusing caches with artifacts is the root of most stage-drift bugs. A cache may legitimately be reused and even regenerated; an artifact must never change after creation, because later stages and environments build their trust on it.

Moving Artifacts Between Stages

A build job produces an artifact; test, deploy, and release jobs consume it. The reliable mechanism is upload in the producing job and download in the consuming job.

yaml
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run build
      - uses: actions/upload-artifact@v4
        with:
          name: web-dist
          path: web/dist
          retention-days: 14

  deploy:
    runs-on: ubuntu-latest
    needs: build
    environment: production
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: web-dist
          path: ./dist
      - run: ./deploy.sh dist

The upload/download pair makes the artifact available as a named unit. Set a retention window so old artifacts do not accumulate forever; you rarely need to redeploy a months-old build.

Cache by Dependency, Never by Artifact

Caching must be keyed on the *input* (the dependency fingerprint), not the *output* it produces. If you cache the artifact computed from a lockfile, then change the lockfile, your cache key diverges and you silently cache an old result. The lockfile checksum should drive the cache key, as covered earlier; artifacts always build fresh.

yaml
      - uses: actions/cache@v4
        with:
          path: ~/.npm
          key: node-${{ hashFiles('package-lock.json') }}
          restore-keys: |
            node-
      - run: npm ci
      - run: npm run build

Notice the flow: cache restore happens before the authoritative install, and the build runs on the freshly installed dependencies. If the cache is stale, the lockfile key changes, the install refreshes it, and the build is correct regardless.

dependencies rarely change cache reused data artifact immutable output install from lock keyed by digest upload once three different lifecycles do not mix their keys

Handle Build Steps with Side Effects

Some build steps produce multiple useful streams: the deployable package, test reports, coverage summaries, source maps that expose internal layout. Upload each as its own named artifact so downstream stages can pull only what they need. Do not stuff everything into one tarball and hope for the best.

When a build step has side effects like writing network state or mutating a shared tool, run it inside a fresh container or working directory so it cannot contaminate the cache or the next build.

Reproducibility Is the Real Goal

Every decision in this post supports one goal: a pipeline whose green result is deterministic — the same commit produces the same artifact, every time, on any runner. Reproducibility collapses when artifacts are built from caches rather than from the canonical inputs, when dependencies drift between runs, or when stages mutate shared state. Guard the artifact as the single source of truth and everything downstream stays coherent.

Takeaway

Cache dependencies by their fingerprint, build artifacts fresh, and pass only immutable artifacts between stages. Treating caches and artifacts as different lifecycles is what keeps multi-stage pipelines fast *and* correct.

For runners with generous disk to hold warm dependency caches and artifact history, Netbay VPS with SSD storage serves well — provision one at netbayhosts.in.

Keep reading

Follow along on a real VPS

Deploy Linux in under 60 seconds

These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.

Deploy an instance