---
title: "Build only what the test or analysis consumes"
description: "Declare the build dependencies of each validation lane so unrelated targets do not join its critical path."
url: https://starsling.dev/ci-playbooks/techniques/build-only-consumed-inputs
canonicalUrl: https://starsling.dev/ci-playbooks/techniques/build-only-consumed-inputs
---

# Build only what the test or analysis consumes

Declare the build dependencies of each validation lane so unrelated targets do not join its critical path.

## 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.

- **[Stripe](https://starsling.dev/ci-playbooks/stripe#build-only-analysis-inputs)**: Use it when A scan builds artifacts, architectures or test bundles that it never analyzes. Check before adopting: The build the analysis reads stays. Keep all analyzed symbols, required architectures, compiler settings and index completeness, and rebuild when the scheme no longer matches what the scan expects.
- **[Uber](https://starsling.dev/ci-playbooks/uber#declare-test-build-inputs)**: Use it when A test target invokes a broad preparatory build even though it exercises only a subset of services. Check before adopting: Declare every runtime input and keep the compile-only gate. Image tags need a hash of the declared contents (the follow-up below), and test-result reuse depends on hermetic inputs and environment.
- **[Uber](https://starsling.dev/ci-playbooks/uber#build-test-targets)**: Use it when A broad test command also builds non-test targets that another required job already compiles. Check before adopting: Check the build tool's exact target-selection rules, keep every discovered test, and keep compile-only targets in a required job.

## Apply this technique

````text
Evaluate and apply this CI technique to my repository: Build only what the test or analysis consumes.

Declare the build dependencies of each validation lane so unrelated targets do not join its critical path.

Read the technique and its source-backed company examples: https://starsling.dev/ci-playbooks/techniques/build-only-consumed-inputs.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.

### Stripe: Build only what the analysis consumes

Stripe iOS stopped packaging XCFrameworks for the API check, which compares arm64 Swift interfaces only. Dead-code scanning builds the SDK frameworks directly and hands the fresh index to Periphery, after verifying the expected SDK roots. Stripe Android’s Financial Connections end-to-end job builds only the release variant it tests.

Evidence: Source PR/commit evidence

Use it when: A scan builds artifacts, architectures or test bundles that it never analyzes.

Before applying it: The build the analysis reads stays. Keep all analyzed symbols, required architectures, compiler settings and index completeness, and rebuild when the scheme no longer matches what the scan expects.

[Read more in the Stripe playbook](https://starsling.dev/ci-playbooks/stripe#build-only-analysis-inputs)

[Primary source](https://github.com/stripe/stripe-ios/pull/7336)

### Uber: Build only the services each test consumes

SubmitQueue stopped building every Linux service before integration and end-to-end tests. Each test declares the cross-compiled binaries, Dockerfiles and configurations it consumes, and a minimal Docker context is staged from those inputs. OPT13 is adapted: the build stays, scoped to declared target dependencies.

Evidence: Source PR/commit evidence

The author reports all nine Docker suites and 79 unit tests passing locally, plus cached test results on a second run. ([Source](https://github.com/uber/submitqueue/pull/439))

Use it when: A test target invokes a broad preparatory build even though it exercises only a subset of services.

Before applying it: Declare every runtime input and keep the compile-only gate. Image tags need a hash of the declared contents (the follow-up below), and test-result reuse depends on hermetic inputs and environment.

[Read more in the Uber playbook](https://starsling.dev/ci-playbooks/uber#declare-test-build-inputs)

[Primary source](https://github.com/uber/submitqueue/pull/439)

### Uber: Build test dependencies in the test lane

SubmitQueue added --build_tests_only to its Bazel unit-test command and kept bazel build //... in a separate required job, so the test lane builds only the test dependency closure.

Evidence: Source PR/commit evidence

The merged Makefile narrows the unit-test build scope, and the separate build job keeps compile-only validation. ([Source](https://github.com/uber/submitqueue/pull/701))

Use it when: A broad test command also builds non-test targets that another required job already compiles.

Before applying it: Check the build tool's exact target-selection rules, keep every discovered test, and keep compile-only targets in a required job.

[Read more in the Uber playbook](https://starsling.dev/ci-playbooks/uber#build-test-targets)

[Primary source](https://github.com/uber/submitqueue/pull/701)

## 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

### [Build before starting the emulator](https://starsling.dev/ci-playbooks/techniques/avoid-emulator-build-contention)

Compile the app first, then boot the emulator and install the finished build.

1 implementation · 1 company (Stripe)

### [Bake stable dependencies into runner images](https://starsling.dev/ci-playbooks/techniques/prebuild-runner-images)

Prepare versioned system dependencies and build downloads once in the runner image instead of installing them on every job.

2 implementations · 2 companies (Anthropic, Linear)

### [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.
