---
title: "Remove repeated build steps"
description: "Trace artifact producers and consumers so package, release, or test stages reuse work instead of triggering the same build again."
url: https://starsling.dev/ci-playbooks/techniques/avoid-duplicate-builds
canonicalUrl: https://starsling.dev/ci-playbooks/techniques/avoid-duplicate-builds
---

# Remove repeated build steps

Trace artifact producers and consumers so package, release, or test stages reuse work instead of triggering the same build again.

## How to choose an approach

Compare the examples by repository setup, prerequisites, and risks before adopting one. Each company implemented this in its own environment; measure each change against your own baseline.

- **[Mastra](https://starsling.dev/ci-playbooks/mastra#release-build-once)**: Use it when A release job builds twice around version or manifest changes. Check before adopting: Keep the build that produces published artifacts after all version changes.
- **[OpenAI](https://starsling.dev/ci-playbooks/openai#avoid-lifecycle-rebuilds)**: Use it when A package lifecycle hook repeats a build in the same job. Check before adopting: Remove the explicit build only when the exact packaging command runs the hook. Disabled hooks or a changed lifecycle would ship a stale package.
- **[Spotify](https://starsling.dev/ci-playbooks/spotify#docker-stage-reuse)**: Use it when A multi-stage Dockerfile or build compiles the same source separately for its build, test and lint stages. Check before adopting: Test and lint now wait for the build stage. Components that need a different build profile keep their own base.
- **[Spotify](https://starsling.dev/ci-playbooks/spotify#drop-artifact-extraction)**: Use it when A job runs a second build only to copy outputs out or print a summary that nothing downstream reads. Check before adopting: Check that no later step, release or reviewer uses the exported files before removing the export.

## Apply this technique

````text
Evaluate and apply this CI technique to my repository: Remove repeated build steps.

Trace artifact producers and consumers so package, release, or test stages reuse work instead of triggering the same build again.

Read the technique and its source-backed company examples: https://starsling.dev/ci-playbooks/techniques/avoid-duplicate-builds.md

Inspect this repository’s CI workflows, build and test commands, dependencies, and recent run timings. Identify where this technique applies and explain the expected benefit using this repository’s evidence.
Measure a baseline from recent comparable runs: elapsed time, queue time, runner minutes and failures where available. If data is unavailable, say what cannot be measured.
Compare relevant company approaches, checking prerequisites, platform differences and tradeoffs. Rank applicable options by evidence, fit and measurable opportunity; do not present company results as predictions for this repo.
Recommend the smallest safe change, show what checks and fallback paths remain, and ASK ME WHICH CHANGE TO APPROVE BEFORE EDITING ANY FILES.
Only after approval, work on a new feature branch, make one reversible change, and open a reviewable pull request. Never merge or push to a default or protected branch.
Keep required checks, test coverage, deployment and release behavior intact. Validate the change and compare equivalent runs where possible; report limitations and what should be monitored after merge.
````

## How companies used this technique

Read what each company changed and follow the original sources.

### Mastra: Build release artifacts after the final version change

Stable publishing removed an early build and kept one build after prerelease exit and installation. Earlier version-PR automation removed builds from the metadata-only versioning step.

Evidence: Source PR/commit evidence

Use it when: A release job builds twice around version or manifest changes.

Before applying it: Keep the build that produces published artifacts after all version changes.

[Read more in the Mastra playbook](https://starsling.dev/ci-playbooks/mastra#release-build-once)

[Primary source](https://github.com/mastra-ai/mastra/pull/22380)

### OpenAI: Let the package lifecycle build once

Codex Security removed the explicit build steps before pnpm pack, because the package's prepack script already runs the build.

Evidence: Source PR/commit evidence

One build per packaging job, run by prepack ([Source](https://github.com/openai/codex-security/pull/397))

Use it when: A package lifecycle hook repeats a build in the same job.

Before applying it: Remove the explicit build only when the exact packaging command runs the hook. Disabled hooks or a changed lifecycle would ship a stale package.

[Read more in the OpenAI playbook](https://starsling.dev/ci-playbooks/openai#avoid-lifecycle-rebuilds)

[Primary source](https://github.com/openai/codex-security/pull/397)

### Spotify: Let test and lint stages reuse the build stage

Confidence's Dockerfile ran each component's test and lint stages as siblings from the same base, so each stage compiled the source on its own. The change adds a build stage per component and derives the test and lint stages from it, letting cargo, Go and Maven reuse the compiled artifacts across six components.

Evidence: Source PR/commit evidence

In a local no-cache Docker build on an Apple M1 Max, total compute across the affected stages fell 61%, from 1807s to 712s. ([Source](https://github.com/spotify/confidence-resolver/pull/355))

Use it when: A multi-stage Dockerfile or build compiles the same source separately for its build, test and lint stages.

Before applying it: Test and lint now wait for the build stage. Components that need a different build profile keep their own base.

[Read more in the Spotify playbook](https://starsling.dev/ci-playbooks/spotify#docker-stage-reuse)

[Primary source](https://github.com/spotify/confidence-resolver/pull/355)

### Spotify: Stop rebuilding just to export artifacts

After the cached Docker build and test step, every Confidence CI run ran a second docker build to export the WebAssembly artifact to the runner, then wrote a step summary listing the artifacts. The change removes both steps from the job.

Evidence: Source PR/commit evidence

Use it when: A job runs a second build only to copy outputs out or print a summary that nothing downstream reads.

Before applying it: Check that no later step, release or reviewer uses the exported files before removing the export.

[Read more in the Spotify playbook](https://starsling.dev/ci-playbooks/spotify#drop-artifact-extraction)

[Primary source](https://github.com/spotify/confidence-resolver/pull/81)

## CI optimization is continuous work.

Apply this technique yourself, or use StarSling Runners for faster GitHub Actions and optional agent-driven optimization PRs, which teams on eligible paid plans can turn on.

[Get self-improving CI](https://starsling.dev/products/runners)

## Related techniques

### [Package once, and build full installers after merge](https://starsling.dev/ci-playbooks/techniques/package-once)

Drop the build step that packaging repeats, and build the unpacked app pull requests test.

1 implementation · 1 company (DoorDash)

### [Run shared validation once](https://starsling.dev/ci-playbooks/techniques/avoid-duplicate-validation)

Remove overlapping task or matrix invocations that perform the same check on the same inputs.

4 implementations · 3 companies (DoorDash, Mastra, Stripe)

### [Cancel superseded pull request runs](https://starsling.dev/ci-playbooks/techniques/cancel-superseded-runs)

Free runner capacity by canceling validation that a newer commit has replaced. Keep required main-branch and release runs intact.

4 implementations · 4 companies (Anthropic, Mastra, Stripe, Uber)

## Company Playbooks

### [Anthropic](https://starsling.dev/ci-playbooks/anthropic)

Run only affected tests

### [DoorDash](https://starsling.dev/ci-playbooks/doordash)

Run build and test in parallel, sharded across CI agents

### [Linear](https://starsling.dev/ci-playbooks/linear)

Benchmark the same job on faster hardware

### [Mastra](https://starsling.dev/ci-playbooks/mastra)

StarSling runners for the slowest test workflow

### [OpenAI](https://starsling.dev/ci-playbooks/openai)

Rank CI fixes by the minutes they save

### [Ramp](https://starsling.dev/ci-playbooks/ramp)

Move a CPU-bound test suite to a faster CPU

### [Shopify](https://starsling.dev/ci-playbooks/shopify)

Let an agent iterate against one CI metric

### [Spotify](https://starsling.dev/ci-playbooks/spotify)

Build arm64 on native arm64 runners

### [Stripe](https://starsling.dev/ci-playbooks/stripe)

Run only the tests a change can reach

### [Uber](https://starsling.dev/ci-playbooks/uber)

Build the merge-queue speculations most likely to be needed

## Related guides

Implementation guides for this technique.

### [Filter workflows by changed files](https://starsling.dev/best-practices/github-actions/path-filter-workflows)

Use paths and job conditions while keeping required checks reporting.

### [Cancel superseded CI runs](https://starsling.dev/best-practices/github-actions/cancel-superseded-runs)

Cancel obsolete PR runs with a correctly scoped concurrency group.

### [Bound runner jobs with timeouts](https://starsling.dev/best-practices/github-actions/bound-job-timeouts)

Set job and step timeouts using expected durations and failure behavior.

### [Right-size GitHub Actions runners](https://starsling.dev/best-practices/github-actions/right-size-runners)

Match runner resources to the workload and compare equivalent runs.
