---
title: "Run only the tests a change can affect"
description: "Use dependency or observed-file relationships to select affected tests, with a full-suite fallback for changes the selector cannot classify."
url: https://starsling.dev/ci-playbooks/techniques/select-affected-tests
canonicalUrl: https://starsling.dev/ci-playbooks/techniques/select-affected-tests
---

# Run only the tests a change can affect

Use dependency or observed-file relationships to select affected tests, with a full-suite fallback for changes the selector cannot classify.

## How it works

Start with the files changed in a pull request, then use the repository’s dependency graph or recorded file usage to identify the tests and build targets that depend on them. Run that affected set for scoped changes. Keep the full-suite path for changes the selector cannot safely classify. The examples below use different selectors, so choose the one that matches your repository’s tooling.

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

- **[Anthropic](https://starsling.dev/ci-playbooks/anthropic#affected-tests)**: Use it when The merge-gating build or test step dominates and existing tooling can compute affected targets. Check before adopting: The scoper falls back to the full suite on an error or an empty result, and the default branch and merge queue keep their full runs. Adapted for GitHub Actions; compare the original system with yours.
- **[Mastra](https://starsling.dev/ci-playbooks/mastra#affected-tests)**: Use it when A monorepo repeatedly tests unrelated packages for small changes. Check before adopting: Follow-ups repaired exported subpaths, merge-base comparisons, Vitest project discovery and JavaScript Vitest configs. Release PRs and alpha publishes run the full suite. Unknown inputs expand to the full suite.
- **[Ramp](https://starsling.dev/ci-playbooks/ramp#build-modified-models)**: Use it when CI builds or tests every model, package or target on each pull request, and the tool can select by state against a saved artifact. Check before adopting: The selection is only as current as the saved state, so save the artifact after every production run and keep a full build on the default branch or a schedule.
- **[Stripe](https://starsling.dev/ci-playbooks/stripe#select-tests-by-observed-files)**: Use it when A large suite runs in full on every change while most changes touch a small part of the code. Check before adopting: Selection is only as complete as the dependency signal. Keep full runs on the default branch, always run tests whose inputs are discovered at runtime, and rerun every test that was red last time. Adapted for GitHub Actions; compare the original system with yours.
- **[Stripe](https://starsling.dev/ci-playbooks/stripe#scope-affected-modules)**: Use it when A monorepo rebuilds and tests modules unrelated to a change. Check before adopting: Shared configuration, generated inputs and test utilities can affect untouched modules. Run the full set for anything the graph leaves unplaced, and keep full validation on the default branch.

## Apply this technique

````text
Evaluate and apply this CI technique to my repository: Run only the tests a change can affect.

Use dependency or observed-file relationships to select affected tests, with a full-suite fallback for changes the selector cannot classify.

Read the technique and its source-backed company examples: https://starsling.dev/ci-playbooks/techniques/select-affected-tests.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.

### Anthropic: Run only affected tests

**Translated to GitHub Actions**

- What Anthropic built: Anthropic's test selection service determines which tests run on each change.
- Your GitHub Actions version: Scope the slowest build or test job to the changed packages and their dependents.

Anthropic picks which tests run on each pull request from package relevance and past results. In GitHub Actions, the same idea scopes the slowest build or test job to the changed packages and their dependents.

Evidence: Documented technique

Use it when: The merge-gating build or test step dominates and existing tooling can compute affected targets.

Before applying it: The scoper falls back to the full suite on an error or an empty result, and the default branch and merge queue keep their full runs.

GitHub Actions adaptation: Compare the source system with your own workflow before applying this translation.

[Read more in the Anthropic playbook](https://starsling.dev/ci-playbooks/anthropic#affected-tests)

[Primary source](https://claude.com/resources/articles/agentic-coding-is-straining-ci-heres-how-we-scaled-test-impact-analysis-at-anthropic)

### Mastra: Route tests through the dependency graph

Mastra evolved from task hashes to a symbol-aware import graph. Runtime and type-test dependencies require separate treatment. This adapts changed-package filtering to test-file selection.

Evidence: Source PR/commit evidence

Use it when: A monorepo repeatedly tests unrelated packages for small changes.

Before applying it: Follow-ups repaired exported subpaths, merge-base comparisons, Vitest project discovery and JavaScript Vitest configs. Release PRs and alpha publishes run the full suite. Unknown inputs expand to the full suite.

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

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

### Ramp: Build only the data models a change modified

Ramp's data CI created an isolated database for each pull request and built every dbt model in it, a full duplicate of production. After each production run, Ramp now saves dbt's manifest.json, and CI builds with --select state:modified+1 against it. Heavy upstream models are cloned from production with zero-copy clones, so CI builds and tests only the modified models and their direct downstream dependencies. The OPT70 recipe scopes a build to changed targets; here the comparison is against the saved production state.

Evidence: Company-reported result or observation

Ramp saw a dramatic dip in the rolling 7 day average cost of its CI warehouses, mostly sustained as pull request volume grew. ([Source](https://builders.ramp.com/post/cost-efficient-snowflake-ci))

Use it when: CI builds or tests every model, package or target on each pull request, and the tool can select by state against a saved artifact.

Before applying it: The selection is only as current as the saved state, so save the artifact after every production run and keep a full build on the default branch or a schedule.

[Read more in the Ramp playbook](https://starsling.dev/ci-playbooks/ramp#build-modified-models)

[Primary source](https://builders.ramp.com/post/cost-efficient-snowflake-ci)

### Stripe: Run only the tests a change can reach

**Translated to GitHub Actions**

- What Stripe built: Stripe instruments its Ruby test runner so every file a test opens is recorded against that test, then reruns the tests whose recorded files changed.
- Your GitHub Actions version: Record the files each test reads, compare the change's file inventory with a recent completed build, and rerun only the tests whose files changed, always including previously failing tests.

Stripe instruments its Ruby test runner so every file a test opens is recorded against that test, including files opened by child processes. For a new change it hashes the file inventory, compares it with a recent completed build and reruns the tests whose recorded files changed. Guardrails always rerun previously failing tests and tests that discover files by globbing, and linters receive the changed-file list.

Evidence: Company-reported result or observation

On average Stripe runs roughly 5% of its full Ruby test suite per build, with a median of 0.5%, using under 10% of the compute of running everything. ([Source](https://stripe.dev/blog/selective-test-execution-at-stripe-fast-ci-for-a-50m-line-ruby-monorepo))

Use it when: A large suite runs in full on every change while most changes touch a small part of the code.

Before applying it: Selection is only as complete as the dependency signal. Keep full runs on the default branch, always run tests whose inputs are discovered at runtime, and rerun every test that was red last time.

GitHub Actions adaptation: Compare the source system with your own workflow before applying this translation.

[Read more in the Stripe playbook](https://starsling.dev/ci-playbooks/stripe#select-tests-by-observed-files)

[Primary source](https://stripe.dev/blog/selective-test-execution-at-stripe-fast-ci-for-a-50m-line-ruby-monorepo)

### Stripe: Select changed modules and their dependents

Stripe iOS re-records snapshots only for modified modules and the modules that depend on them, walking Xcode target links including shared test utilities. SDK size reports check only affected SDKs and their dependents. When the selection is uncertain, both run in full.

Evidence: Source PR/commit evidence

In Stripe’s combined CI runs, framework tests went from about 22 to about 12 to 14 minutes, and snapshots and localization from about 15 to about 13 to 14 minutes, with the related build and job changes. ([Source](https://github.com/stripe/stripe-ios/pull/7332))

Use it when: A monorepo rebuilds and tests modules unrelated to a change.

Before applying it: Shared configuration, generated inputs and test utilities can affect untouched modules. Run the full set for anything the graph leaves unplaced, and keep full validation on the default branch.

[Read more in the Stripe playbook](https://starsling.dev/ci-playbooks/stripe#scope-affected-modules)

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

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

### [After the first full agent scan, review only what changed](https://starsling.dev/ci-playbooks/techniques/scan-only-the-diff)

Run the full agent review once and keep its artifacts, then compare each new commit with the previous one and scan only the changes.

1 implementation · 1 company (Shopify)

### [Install and build only the workspace packages a job uses](https://starsling.dev/ci-playbooks/techniques/scope-workspace-builds)

Scope dependency installation and builds to the package or lane under test, including its actual dependencies.

3 implementations · 3 companies (Linear, Mastra, Shopify)

### [Move selected heavy checks after merge](https://starsling.dev/ci-playbooks/techniques/defer-heavy-validation)

Keep a deliberately chosen pull request gate and schedule heavier validation after merge, with explicit ownership of the resulting risk.

2 implementations · 2 companies (OpenAI, Shopify)

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

### [Build and test only what changed](https://starsling.dev/best-practices/github-actions/build-only-affected)

Scope work with your dependency graph and keep a full-run fallback.

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

Use concurrency groups to keep PR verification focused on the latest commit.

### [Cut CI queue time](https://starsling.dev/best-practices/github-actions/cut-queue-time)

Measure waiting time and identify concurrency or capacity constraints.

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

Distinguish workflow triggers from job-level conditions for required checks.
