Engineering ProductivityOct 16, 202611 min read

Stacked PRs: what they are and how to run CI on a stack

Jacob Schmitt

Senior Technical Content Marketing Manager

Large pull requests can be a pain to review. When a change touches dozens of files and adds hundreds of lines of code, reviewers have a lot to work through before they can approve it. And if something needs to change, the whole PR goes through another round of review.

Stacked PRs let developers split a large change into smaller, dependent pull requests that can be reviewed separately. GitHub made stacked PRs generally available in October 2026, with support for managing stacks through GitHub or its gh-stack CLI extension.

But smaller PRs don’t necessarily mean less work for continuous integration (CI). Each branch has its own checks, and updating an earlier PR can trigger new pipelines across the rest of the stack. Here’s how stacking works, what changes for CI, and how to avoid repeating builds and tests unnecessarily.

What is a stacked PR?

A stacked pull request is a PR whose base branch is another PR’s branch rather than main. Each PR builds on the one below it, so developers can split a large change into smaller pieces that reviewers can evaluate separately.

Say you’re adding rate limiting to an API. You need to update the config schema, add middleware, connect it to the request handlers, and write integration tests. You could put everything in one large PR, or split the work into four:

main
 └── ratelimit-config                   PR #1
      └── ratelimit-middleware          PR #2
           └── wire-handlers            PR #3
                └── integration-tests   PR #4

Each PR targets the branch directly below it. Reviewers can approve the config changes in PR #1 without having to review the middleware or integration tests at the same time. Meanwhile, the developer can keep working on the later PRs.

As the earlier PRs merge, the remaining branches are updated to reflect those changes. Stacked PRs are sometimes called stacked diffs, a term used by earlier code review systems such as Phabricator.

Why use stacked PRs?

Smaller PRs are generally easier to understand and review. Reviewers can focus on one part of a change, developers get more specific feedback, and it’s easier to identify which change introduced a problem.

Stacking works well when one change depends on another. A developer doesn’t need to wait for the first PR to merge before starting the next, and reviewers can work through the changes separately.

Coding agents make it easier to produce large changes quickly, but reviewing all that code is another matter. Breaking the work into smaller PRs can help, especially when agents run tests and fix problems before pushing changes.

How stacked PRs affect CI

Every PR in a stack needs validation. With four branches, you may have four sets of builds, tests, and required checks running on changes that share much of the same code.

Things get more expensive when you update an earlier PR.

Suppose a reviewer requests an update to ratelimit-config, the first branch in our example. You make the change, then rebase the branches above it. Pushing those branches can trigger another round of pipelines across the stack.

main
 └── ratelimit-config                   Updated → CI
      └── ratelimit-middleware          Rebased → CI
           └── wire-handlers            Rebased → CI
                └── integration-tests   Rebased → CI

Depending on your Git workflow and CI triggers, a change to one PR can result in several new pipelines. GitHub can merge a stack through its merge queue as a single group, but changes to the underlying commits still need fresh validation.

Some of that validation is necessary. If the config schema changes, you’ll want to confirm that the middleware and request handlers still work with it. But running unrelated builds and tests on every branch adds cost without necessarily catching more problems.

How to run CI efficiently on stacked PRs

You don’t need to run a complete build and test suite for every update. CircleCI gives you several ways to avoid unnecessary jobs, run fewer tests, and catch problems before code gets pushed.

Here’s where you can cut unnecessary CI work without losing important checks.

Technique What it saves What it doesn’t
Path filtering Unnecessary CI jobs Tests inside selected jobs
Smarter Testing Unnecessary tests and repeated work All tests affected by earlier stack layers
Dynamic Parallelism Excess compute for smaller test suites Required test execution
Chunk sidecars CI runs for errors caught before pushing Post-push validation
Agent-assisted debugging Time spent investigating CI failures CI runs needed to verify fixes

1. Run only the jobs affected by each PR

Consider a monorepo containing several backend services, a frontend application, and shared libraries. If a PR only changes the API middleware, it probably doesn’t need to trigger a frontend build.

CircleCI’s dynamic configuration lets you select jobs based on which files have changed. With path filtering, you can run the jobs associated with the affected directories without running every workflow in the repository.

For example, the path-filtering orb can map changes in the API and frontend directories to different pipeline parameters:

version: 2.1
setup: true

orbs:
  path-filtering: circleci/path-filtering@1

workflows:
  generate-config:
    jobs:
      - path-filtering/filter:
          base-revision: ratelimit-config
          config-path: .circleci/continue-config.yml
          mapping: |
            api/.*       run-api-tests      true
            frontend/.*  run-frontend-build true

Here, ratelimit-middleware compares its changes against ratelimit-config, the branch directly below it. A change to the API middleware can trigger the API tests without rebuilding the frontend. The continuation config uses those parameters to choose which jobs to run.

Use the parent branch as the comparison point. If every branch in a stack compares against main, the diff can include changes introduced by all the earlier PRs. Jobs associated with those changes may run again even though the current PR hasn’t modified that code.

The example uses a fixed parent branch to show how the comparison works. For a reusable setup, you’ll need to determine each PR’s base branch, for example using GitHub’s API, and pass that revision to your setup workflow. The bottom PR compares against main, while later PRs compare against their immediate parents.

2. Run fewer tests with Smarter Testing

Even when a PR triggers only the relevant jobs, those jobs may still run thousands of tests. For a small change to one middleware function, running the entire API test suite on every rebased branch can add substantial time and compute usage.

CircleCI’s Smarter Testing provides three capabilities that help:

  • Test impact analysis uses code coverage data to identify tests affected by source code changes, allowing you to skip tests that don’t cover the modified code.
  • Dynamic test splitting distributes tests across parallel nodes as they run, so nodes that finish early can take on additional work.
  • Auto-rerun failed tests retries failed tests during the same job, helping distinguish intermittent failures from problems that need investigation.

If only a fraction of your tests cover the affected code, test impact analysis can select those tests instead of running the entire suite.

Test impact analysis considers changes across the stack. CircleCI uses coverage data collected on the default branch to select tests. Because an upper branch contains changes from every layer below it, test selection may include code introduced by earlier PRs. Unlike parent-branch path filtering, test impact analysis doesn’t necessarily isolate the changes in the current layer.

Smarter Testing lets you rerun only failed tests when restarting a failed workflow, without repeating tests that already passed. That capability is free, while advanced features such as test impact analysis, dynamic splitting, and automatic retries use credits beyond your plan’s monthly allowance.

See Getting started with Smarter Testing for setup instructions.

3. Match compute to the number of tests

Say your full test suite normally runs on 20 containers, but test impact analysis selects only a handful of tests for a small PR. Starting all 20 containers would waste compute.

CircleCI’s Dynamic Parallelism, introduced in October 2026, lets you scale the number of parallel nodes to match the work.

You can scale the maximum node count by the share of the test suite selected, so a small change uses fewer nodes. Or set a target duration, such as two minutes, and let CircleCI calculate the number of nodes needed. Both options stay within the minimum and maximum you configure.

For stacked PRs, test impact analysis selects the relevant tests, dynamic splitting distributes them across nodes, and Dynamic Parallelism adjusts how many nodes you start.

Dynamic Parallelism is currently experimental, and its config syntax may change. Like the other advanced Smarter Testing features, it uses test-atom credits beyond your plan’s allowance.

4. Catch failures before pushing

Developers can avoid some CI runs entirely by catching failures before pushing. That’s especially useful when coding agents are making changes across several branches. An agent might introduce a syntax error or break a unit test, then push the code and leave CI to discover the problem.

Chunk sidecars give coding agents a lightweight Linux microVM for validating code during development. The sidecar works alongside the agent’s local workflow, providing feedback before the developer commits or pushes the change.

You can use agent hooks to trigger validation at specific points. A pre-commit hook can run local tests before the agent commits, while a stop hook can run chunk validate when the agent finishes its turn.

If validation fails, the agent gets the test output and can work on a fix while the code is still in context. Developers can review the proposed changes and push them once they’re ready.

For stacked PRs, catching a failure on a lower branch before pushing can prevent an unnecessary round of failing pipelines on the branches above it. Sidecars don’t replace your regular CI checks, but they can help keep routine failures out of them.

5. Help agents fix failures that reach CI

Some failures only show up in CI. A change might work on its own but fail when integrated with another branch, or a test might behave differently in the CI environment.

When a pipeline fails, the CircleCI CLI can pull together diagnostic output from failed steps without requiring developers to open several jobs and search through the logs:

circleci run get --failure-report <run-id>

The command pulls together failure details from the run, including errors across multiple jobs. The CircleCI CLI also has a built-in MCP server, so compatible coding agents can retrieve CI information directly.

If you’re using Claude Code, CircleCI provides a Fix with Claude Code action in the UI. Select the wrench icon on a failing workflow to open Claude Code in your terminal with a preloaded failure-diagnosis workflow.

For other agents, CircleCI provides a Copy Fix Prompt option you can paste into your preferred coding agent.

The agent can use the failure report to investigate the problem and propose a fix. You can review the change and run CI again to verify it works. For a stacked PR, this can save time when an update to an earlier branch introduces a failure farther up the stack.

Keep the checks that matter

Every PR in a stack still needs enough validation to merge safely. You shouldn’t rely entirely on the integration tests in PR #4 to catch problems introduced by the middleware in PR #2. The middleware should pass its own required checks before merging, even if later integration tests provide additional coverage.

Some tests may still need to run across multiple layers, particularly when changes affect shared libraries, interfaces, or interactions between services.

Path filtering, test impact analysis, and Dynamic Parallelism help reduce the work each pipeline performs. Pre-push validation and agent-assisted debugging can reduce the number of times developers need to run CI to reach a passing result.

When should you use stacked PRs?

Stacked PRs work best when a large change can be broken into smaller pieces that reviewers can understand separately. They’re useful when developers want to keep working on dependent changes while earlier PRs are under review.

For a small change, a single PR is usually easier. And if reviewers need to understand the entire feature before they can evaluate any individual PR, splitting the code may create more review work rather than less.

The longer a stack stays open, the more likely you’ll have to deal with changes landing on main. You may end up resolving conflicts and rebasing several branches before the changes are ready to merge.

If managing the stack takes more time than reviewing one larger PR would, you’re probably better off keeping the change together.

Get started

Before adopting stacked PRs, check whether your CI setup runs unnecessary jobs and tests. Path filtering and Smarter Testing can help reduce repeated validation, while Dynamic Parallelism can keep compute usage in line with the number of tests selected.

If your team uses coding agents, Chunk sidecars can catch problems before pushing, and the CircleCI CLI can help agents investigate failures that reach CI.

See dynamic configuration, Smarter Testing, and Chunk sidecars to get started, or sign up for a free CircleCI account to try them out.

Frequently asked questions

What is a stacked PR?

A stacked pull request is a PR whose base branch is another PR’s branch instead of main. Each PR builds on the one below it, allowing developers to split a large change into smaller pieces that can be reviewed and merged separately. Stacked PRs are sometimes called stacked diffs.

Does GitHub support stacked PRs?

Yes. GitHub made stacked pull requests generally available in October 2026. You can manage them through GitHub’s interface or the gh-stack CLI extension. GitHub supports required checks, approvals, and merge queues for stacked PRs.

Stacked PRs vs. one big PR: which should I use?

Use stacked PRs when you can split a large change into smaller pieces that reviewers can evaluate independently. A single PR is generally simpler for smaller changes or work that can’t be meaningfully separated.

Stacking can help developers continue working while earlier changes are under review, but it requires more branch management and can increase CI usage.

How do stacked PRs work with CI?

Each branch in a stack can trigger its own CI pipeline. Updating an earlier PR may require rebasing the branches above it, which can trigger additional builds and tests.

With CircleCI, you can use dynamic configuration and path filtering to run the jobs each PR needs, Smarter Testing to reduce test execution, and Dynamic Parallelism to match compute to the selected tests. Chunk sidecars can catch failures before pushing, while the CircleCI CLI helps developers and coding agents investigate failures that reach CI.