Background gradient
How to use stacked PRs to unblock your entire team HERO image

Imagine this—you just wrote a new profile customization feature for your app, addressing all the edge cases and optimizations. The feature encompassed hundreds of lines of code, across dozens of files. You changed the database, the frontend UX, and how requests are handled from client to server. In other words... it’s a significant change. 

You submit the massive pull request (PR) for review and…you’re blocked. You can’t move on to the next feature until this mega PR gets reviewed and merged. 

So, you have two options:

  1. Switch to the backlog, stalling delivery of high-priority tasks

  2. Repeatedly ping your coworkers, begging for a quicker review.

If only you had submitted work in a smaller PR...

Enter stacking

The largest technology companies like Meta have used “stacked pull requests” for years to accelerate engineering. This approach involves splitting large code changes into manageable chains of small stacked PRs, helping you rapidly build new features by simply stacking branches on top of the previous ones. 

With this approach, you no longer have to wait for the code review process to complete—fully unblocking you. Let’s understand stacking in more detail, how it can benefit the team, and how better tooling can further improve the workflow. 

Stacked pull requests are like making layered cakes. You start with one solid foundation—the main branch. On top of this base branch, you add your first layer—a small, focused code change. While the first layer is being reviewed, you can start on the second layer. As the layers get completed, they’re added one after the other on top of the base branch—giving you the entire cake—without being blocked on each layer to be finalized and approved before starting the next.

That’s the idea behind stacking—break large features into many tiny pull requests and build them on each other like blocks. Each small PR can be tested, reviewed, and merged independently.

To put things in perspective, let’s take an example of an e-commerce checkout flow. Instead of a single large PR with hundreds of lines of code, you can break the checkout flow into several smaller PRs:

  • PR 1: Checkout button

  • PR 2: Checkout form 

  • PR 3: Integrate checkout with payment gateway

  • PR 4: Handle order submission and completion

The best part? You can work on each component without waiting around for reviews. 

The code is directly branched off the previously created PR (for instance, PR 2 is built upon the code in PR 1) instead of the main branch. This eliminates the need to wait for the code to be merged into main before the next feature can be built.

As the PRs are small, reviews are both quicker and more thorough, getting the PRs merged with the main branch faster and with fewer bugs.

Let’s look at some of the other benefits of stacking PRs.  

Adopting a stacked pull request workflow provides several key advantages that enable faster, smoother software delivery cycles.

With a stacked PR workflow, you can open your first PR with small changes, submit it for review, and create a second branch on top of the previous one while the first PR gets reviewed. 

This approach avoids development bottlenecks and ensures a smooth, uninterrupted workflow.

For example, let’s go back to our e-commerce flow.

  • Your first PR implements just the checkout button on the cart page. 

  • The following PR has the form elements. 

  • The third does order processing from the form data. 

At each of these steps, you can continue building the next change without waiting for the previous PRs to be approved and merged. This approach prevents you from being blocked for hours or even days while you wait for review on a 1000+ line pull request encompassing all of these changes.

Debugging is simplified when you isolate changes. 

Say your giant PR unexpectedly breaks the payment gateway. Good luck digging through hundreds of edits across 20 files to find the culprit! 

With stacked PRs, any issues that appear would be limited to the last set of focused changes. Since the PRs are fewer than 200 lines, it becomes vastly easier to identify what went wrong and revert the change.

Instead of one huge change that breaks your e-commerce flow, you'd have the flexibility to quickly test after each incremental component—checkout button, checkout form, order processing—which makes identifying and fixing issues simple.

It's common to see software engineers delay or completely skip reviewing large PRs with over 1000 lines of code.

With stacking, however, reviews become focused and efficient. Reviewers can more easily comprehend the scope when a PR touches five files instead of 50, leading to faster and higher-quality feedback.

For example, to understand how the checkout flow impacts the order processing database and post-purchase functions, you’d need to dig through multiple layers of a single PR. 

However, in a stacked world, you'd have a PR for each context—checkout button, form and UI, and order processing—much simpler to digest, reducing the overall review time.

Now, how do you implement this stacking workflow for your team?

Moving to a stacked pull request workflow will be challenging—especially when your team is used to a certain way of operating. 

But, once the team understands the workflow, it can significantly improve developer productivity

Stacking means developers stay laser-focused on writing the features—without having code review blocking their progress. Changes begin to flow smoothly from local branches into testing and out to production faster than ever.

The transition does require some patience and teamwork. Here’s how to start:

  • Assess the team’s trunk-based development maturity. Ensure developers are comfortable with concepts like rebasing over merging, using short-lived branches, and rapid integration before layering on stacking.

  • Get buy-in by communicating benefits. Show how stacking addresses pain points like long-lived branches and delayed reviews. Demonstrate how it leads to faster deployments, fewer blockers, and happier developers.

  • Define team-wide stacking specifications upfront to align expectations. Standardize practices like review timelines  (<24 hrs), and pull request sizes (<200 LOC). 

Integrating stacking-focused code review tools can also help you make the transition faster. 

For instance, tools like Graphite, help your team create and submit stacks from the command line —while automating a lot of the complexity behind-the-scenes.

And while you can use GitHub for stacking PRs, achieving the same result requires many additional steps. Here’s a quick stacking workflow with GitHub and Graphite. 

Let’s suppose you want to build a “dark mode” feature for the checkout flow. You break it into two separate PRs—dark mode toggle button and dark mode theme. 

Let’s run through a typical stacking workflow with GitHub vs Graphite for the same feature.

First, create the initial parent PR:

Terminal
// Start point is main branch
git checkout -b dark-mode-toggle
// Implement toggle UI component, then add the file.
git add DarkModeToggle.js
git commit -m "Feature: Add dark mode toggle UI"
// Creates PR #1 - the Parent
git push -u origin dark-mode-toggle

Next, let’s stack two child PRs on top:

Terminal
// Checkout the parent PR
git checkout dark-mode-toggle
// Create the child PR
git checkout -b dark-mode-styles
// Implement the dark mode styles and styling elements
git add DarkModeStyles.css
git commit -m "Feature: Styling dark mode"
git push origin dark-mode-styles
// Create second child PR
// while you’re checked out on dark-mode-styles (first child)
git checkout -b dark-mode-transitions
// Implement the transitions
git add DarkModeTransitions.js
git commit -m "Feature: Add theme transitions"
git push origin dark-mode-transitions

There are two issues with the above:

  • There is no way to link PRs; you have to manually note changes in commit messages

  • If changes are made to the parent, you have to rebase all of the child branches

If the review finds a bug in your code and you update the parent branch, dark-mode-toggle, you’re left with dependent child branches, dark-mode-styles, and dark-mode-transitions that still have the old code. 

That’s when git rebase comes in handy. 

While it requires manual effort, you’ll benefit from having smaller PRs here, and the changes must be applied to all branches upstream.

Terminal
// Checkout the parent branch
git checkout dark-mode-toggle
// Reviewer comments on the parent branch
// You make changes and push code to the parent branch
git add DarkModeToggle.js
git commit -am "BugFix: Fix padding based on feedback"
git push origin dark-mode-toggle
// You now need to make upstream changes
// Manually rebase child branches on updated parent
git checkout dark-mode-styles
git rebase dark-mode-toggle
// Rebase the second child and continue doing so for all branches
git checkout dark-mode-transitions
git rebase dark-mode-styles

There are some other challenges with GitHub stacking:

  • It requires tedious branch switching and rebasing

  • There can be merged conflicts across long branch chains

  • It's difficult to visualize the dependency graph

As you can see, manually managing dependent pull requests introduces overhead around propagating changes across branches. Let’s look at how Graphite makes stacking workflows easier. 

Once you’ve installed Graphite CLI, navigate to your repo. 

Now, you can start building your feature in multiple parts. Assuming we already made all our code changes in our DarkModeToggle.js file, let’s create the “Add dark mode toggle UI” feature branch.

Terminal
// Modify your files since the next command will
// create a new branch with your changes off of the branch
// you’re currently at
gt create -am "Feature: Add dark mode toggle UI"

The above command automatically creates a new branch, commits staged changes, and writes a commit message. The gt submit command will push the changes to the remote repo.

Once you’re done, you can start working on the next feature. Once you have staged the changes for your next feature, run the following command. Graphite will automatically stack the PR on top of the branch you’re on.

Terminal
// Make changes while you’re on the toggle UI branch
// Then run the below command to create a new child branch with the changes
gt create -am "Feature: Styling dark mode"

Let's say you make a code change to the parent branch that adds the dark mode toggle UI. Graphite gives you a handy gt modify command for when you need to address feedback.

Terminal
// Checkout the branch that received review comments
// Make changes to the required files and then
// run the following command
$ gt modify -a
[01-04-Feature_Add_dark_mode_toggle_UI f24cf74] Feature: Add dark mode toggle UI
1 file changed, 1 insertion(+)
Restacked 01-04-Feature_Styling_dark_mode on
01-04-Feature_Add_dark_mode_toggle_UI.
Restacked 01-04-Feature_Add_theme_transitions
on 01-04-Feature_Styling_dark_mode.

As you can see, the gt modify command handles restacking of dependent branches with no additional commands. On Git, you’d have to identify the stacked branches and rebase them individually. 

When you’re all done, you can simply run gt submit.

Terminal
$ gt submit
🥞 Validating that this Graphite stack is ready to submit...
✔ How would you like to proceed? > Continue with empty branches
✏️ Preparing to submit PRs for the following branches...
▸ 01-04-Feature_Add_dark_mode_toggle_UI (Create)
✔ Title ... Feature: Add dark mode toggle UI
✔ Body > Skip (leave empty)
✔ Submit > Create Draft Pull Request
▸ 01-04-Feature_Styling_dark_mode (Create)
✔ Title ...
✔ Body > Skip (leave empty)
✔ Submit > Create Draft Pull Request
▸ 01-04-Feature_Add_theme_transitions (Create)
✔ Title ...
✔ Body > Skip (leave empty)
✔ Submit > Create Draft Pull Request
📨 Pushing to remote and creating/updating PRs...

This will prompt you with a few questions:

  • Whether you want to edit the PR description now

  • If you select yes, it will open the PR description in your $EDITOR for editing.

  • Whether you want a draft PR or to publish it immediately

When the gt submit is complete, it prints out the URL of the newly created pull request. You can either directly click the URL or run gt pr to open the new PR quickly in your default browser. 

Graphite also lets reviewers merge the dependent branches automatically instead of manually going through the individual pull requests—making the overall process streamlined.

GitHub requires manual management of dependencies between branches during stacking workflows. Developers must handle mundane and error-prone rebasing and tracking of relationships between changes.

In contrast, Graphite automates branch coordination—from creating connected features to propagating updates across the stack. This streamlines development, saving effort on mechanical git operations. Beyond simplifying change tracing and submission workflows, Graphite also visualizes relationships between increments of work.

Stacked pull requests offer transformative benefits over traditional monolithic PRs by unblocking teams on code review. You get enhanced code quality, faster innovation cycles, thorough reviews and testing, and an overall boost in team productivity.

But like any process, effective implementation will require care. Spend time to set consistent rules for small PR sizes, descriptive names, automation tools, and more. Set your team up for success by following proven best practices—and ensure these practices are followed across the board.

Soon, you'll be reaping the rewards of faster, higher-quality delivery thanks to removing the roadblock of mega-pull requests. 

Ready to try stacking to unblock your team, blow past bottlenecks, and unleash team productivity? Sign up free and test your workflow on Graphite today!