Trunk-Based Development
Complete the full lesson to earn 25 points
Work through each section, then tap “Mark as Complete” on the last one.
Mastering Trunk-Based Development: A Strategy for High-Velocity Teams
Introduction: Why Branching Strategies Matter
In the world of software engineering, the way a team manages its source code repository is often the single biggest factor in how quickly and reliably they can deliver features to users. Many teams start their journey with complex branching models, such as GitFlow, which involve long-lived feature branches, release branches, and hotfix branches. While these models provide a clear structure, they often introduce significant friction, leading to "merge hell" and delayed feedback loops. As systems grow in complexity, the time spent managing branches often outweighs the time spent writing code.
Trunk-Based Development (TBD) is a strategy that flips this traditional model on its head. Instead of isolating developers in their own long-lived branches for weeks at a time, TBD encourages all team members to merge their changes into a single, shared branch—the "trunk"—multiple times a day. This approach forces developers to break down their work into smaller, incremental chunks that can be integrated quickly. By keeping the trunk in a deployable state at all times, teams eliminate the massive integration headaches that plague traditional workflows.
This lesson explores the mechanics of Trunk-Based Development, why it is the preferred choice for high-performing organizations, and how you can implement it in your own team. We will move past the theoretical benefits and dive into the practical application, covering everything from feature flagging to automated testing requirements. Whether you are working on a small internal tool or a massive distributed system, understanding TBD is essential for modern, sustainable software delivery.
The Core Philosophy: What is Trunk-Based Development?
At its simplest, Trunk-Based Development is a version control management practice where all developers merge small, frequent updates to a core "trunk" or "main" branch. The primary goal is to minimize the divergence between a developer’s local work and the shared codebase. When code stays on a private branch for too long, it drifts further away from the current state of the product, making the eventual merge process exponentially more difficult and error-prone.
In a TBD environment, you rarely see branches that live for more than a day or two. If a task takes longer than that, the developer is expected to break it into smaller sub-tasks or use architectural techniques like abstraction to merge partially completed work without breaking the production build. This requires a shift in mindset: the focus moves from "finishing a feature" to "integrating a small, safe piece of the feature."
Callout: Trunk-Based Development vs. GitFlow GitFlow relies on long-lived branches for features, releases, and hotfixes, which often leads to complex merge conflicts when features are finally integrated. Trunk-Based Development, conversely, focuses on a single primary branch, utilizing feature flags to hide incomplete work from users. While GitFlow provides a sense of security through isolation, TBD provides security through constant, small-scale integration and automated validation.
Key Principles of TBD
- Single Source of Truth: The trunk is always the authoritative version of the software.
- Short-Lived Branches: If branches are used, they are deleted almost immediately after being merged back to the trunk.
- Frequent Commits: Developers push code to the trunk several times a day.
- Automated Verification: Because integration happens so often, a robust suite of automated tests is non-negotiable to ensure the trunk remains stable.
The Mechanics of Implementation
Implementing Trunk-Based Development is not just about changing how you use Git commands; it is about changing how you design and test your software. If you attempt to use TBD without the supporting infrastructure, you will likely end up with a broken trunk and frustrated developers.
1. Breaking Down Work
The biggest hurdle for many teams transitioning to TBD is the tendency to work on large, monolithic features. If you are building a new authentication system, you cannot simply push half-finished code that breaks login for existing users. You must learn to decompose your work into small, functional units. For example, instead of "implementing OAuth," you might start by creating the database schema, then the API endpoints (returning static data), then the actual authentication logic, and finally the client-side integration.
2. Feature Flags (Toggles)
Feature flags are the "secret sauce" of TBD. They allow you to merge code into the trunk that is not yet ready for the end-user. By wrapping new functionality in a conditional statement, you can safely deploy the code to production while keeping it disabled for everyone except perhaps a small group of internal testers.
// Example of a Feature Flag in JavaScript
if (featureFlags.isNewCheckoutEnabled()) {
renderNewCheckoutUI();
} else {
renderLegacyCheckoutUI();
}
By merging this code into the trunk, you ensure that your work is being continuously integrated with the work of your teammates. If a conflict arises, you catch it within hours, not weeks. Once the feature is ready, you simply toggle the flag to "on" for all users and eventually remove the else block to clean up the code.
3. The Role of Automated Testing
In a TBD workflow, you lose the "safety net" of long-lived integration branches. You must replace that with a comprehensive automated test suite. Every time a developer pushes to the trunk, a Continuous Integration (CI) pipeline should automatically run tests. If the build fails, the team must prioritize fixing it above all other tasks. This creates a culture of accountability where the health of the codebase is everyone’s shared responsibility.
Note: Do not mistake "committing to the trunk" as "deploying to production." You can use CI/CD pipelines to run automated tests on the trunk without automatically pushing that code to your live user base.
Step-by-Step: A Typical TBD Workflow
To illustrate how this looks in practice, let’s walk through a standard developer workflow in a TBD environment.
- Pull the Latest: Before starting any work, the developer pulls the latest changes from the
mainbranch to ensure their local environment matches the current state of the team’s work.git checkout main git pull origin main - Create a Short-Lived Branch: The developer creates a branch for their specific task, but they intend to merge it back within a few hours.
git checkout -b feature/user-profile-update - Implement and Test: The developer writes the code, ensuring that they run local tests to verify their changes do not break existing functionality.
- Rebase and Resolve: Before merging, the developer rebases their branch against
mainto incorporate any changes that were merged by colleagues while they were working.git fetch origin git rebase origin/main - Merge to Trunk: Once the tests pass locally, the developer pushes their changes to the trunk. If the team uses Pull Requests (PRs), this is the point where a peer review occurs.
git checkout main git merge feature/user-profile-update git push origin main - Delete the Branch: The feature branch is now obsolete and should be deleted immediately.
Best Practices for Success
Transitioning to TBD requires discipline. Without clear standards, the trunk can quickly become a graveyard of broken builds and half-finished logic.
Maintain a "Green" Trunk
The most important rule in TBD is that the trunk must always be in a deployable state. If you break the build, you are effectively blocking every other developer on the team from doing their work. If you find yourself needing to commit code that is not quite ready, use feature flags or hide the code behind an unused entry point in your application.
Keep Pull Requests Small
If your team requires code reviews, ensure that the scope of each pull request is minimal. A PR that contains 500 lines of code is much harder to review than one that contains 50 lines. Smaller PRs also move through the review process faster, which is critical for maintaining the momentum required by TBD.
Invest in CI/CD Infrastructure
Automated testing is the backbone of TBD. Your CI pipeline should be fast, reliable, and provide clear feedback. If your tests take two hours to run, developers will not run them before merging, and the trunk will eventually break. Focus on writing unit tests that execute in seconds and integration tests that run in minutes.
Use "Branch by Abstraction"
When you need to make a massive change to an existing system, such as replacing a core database or a legacy library, do not create a long-lived branch. Instead, use an abstraction layer to decouple the new implementation from the old one. You can then toggle between the two implementations using flags, allowing you to merge the new, unfinished code into the trunk safely.
Warning: Avoid the "Golden Branch" trap. Some teams claim to do TBD but then create a "development" branch that is never merged to the main branch for weeks. This is not TBD; it is simply a different flavor of long-lived branching. Stick to the actual
mainortrunkbranch.
Common Pitfalls and How to Avoid Them
Even with the best intentions, teams often struggle when moving to TBD. Here are the most common mistakes and how to navigate them.
1. The "Big Bang" Merge
The Problem: A developer works for three days on a feature, ignoring the trunk, and then tries to merge a massive amount of code that conflicts with everything else. The Fix: Enforce a "daily merge" culture. Encourage developers to commit their work-in-progress to the trunk, even if it is incomplete. Use feature flags to ensure that the code has no impact on the end-user. If the work is too large, break it down into smaller, independently mergeable segments.
2. Ignoring Test Failures
The Problem: The CI pipeline reports a failure, but the team ignores it and continues merging code, assuming it’s a "flaky test." The Fix: Treat a broken build as a "stop the line" event. No new code should be merged until the build is fixed. If a test is truly flaky, it should be removed or refactored immediately. A culture that ignores test failures will eventually lead to a system where no one trusts the automated suite.
3. Lack of Communication
The Problem: Two developers work on the same module simultaneously without realizing it, leading to wasted effort and complex conflicts. The Fix: TBD relies on high-bandwidth communication. Use tools like Slack or stand-up meetings to announce what you are working on. If you are planning a significant refactor that will affect a core module, let the team know before you start.
4. Over-reliance on Manual Testing
The Problem: The team relies on QA engineers to manually verify every merge. This creates a bottleneck that makes frequent integration impossible. The Fix: Move toward a "Quality at the Source" model. Developers should be responsible for writing the tests that verify their code. QA should focus on exploratory testing and edge cases rather than regression testing.
Comparison: Branching Strategies
Understanding where TBD fits in the landscape of version control is helpful for choosing the right strategy for your team.
| Strategy | Branch Lifespan | Merge Frequency | Best For |
|---|---|---|---|
| GitFlow | Long (weeks/months) | Low (at release) | Teams with strict, infrequent release cycles. |
| GitHub Flow | Medium (days) | Moderate | Small teams with frequent, continuous deployments. |
| Trunk-Based | Very Short (hours) | Very High (daily) | High-velocity teams using CI/CD. |
| Forking Workflow | Varies | Varies | Open-source projects with external contributors. |
Deep Dive: Handling Complex Refactors
One of the biggest concerns developers have about TBD is how to handle large-scale refactoring. If you are changing a fundamental API that is used across the entire application, how do you keep the trunk stable?
The technique for this is called Branch by Abstraction. Let’s say you want to replace a legacy logging service with a new, high-performance one.
- Create an Interface: Create an interface that defines the logging methods your app needs.
- Implement the Legacy Wrapper: Create an implementation of that interface that calls the old logging service.
- Update the Application: Update your application code to use the interface instead of the direct legacy service calls. This is a safe refactor because the behavior hasn't changed.
- Add the New Implementation: Create a new class that implements the interface and uses the new logging service.
- Toggle the Implementation: Use a configuration setting or a feature flag to switch between the legacy wrapper and the new implementation.
- Test and Verify: Turn on the new implementation for a small percentage of requests or in a staging environment.
- Clean Up: Once the new service is proven to be stable, delete the legacy wrapper and the old logging code.
By following this process, you never break the trunk. You are constantly merging small, safe, and reversible changes. This is the heart of professional-grade software engineering.
The Role of Code Review in TBD
In a TBD environment, code reviews serve a different purpose than in traditional models. Instead of reviewing a massive feature to ensure it doesn't break anything, the reviewer is checking for architectural consistency, code quality, and potential edge cases in a small, incremental change.
To make this work efficiently, consider these practices:
- Pair Programming: Many TBD teams use pair programming to conduct "real-time" code reviews. This eliminates the wait time associated with asynchronous PRs.
- Automated PR Gates: Use automated tools to enforce linting, formatting, and test coverage requirements. If a PR doesn't meet these standards, it shouldn't even be looked at by a human.
- Prioritize Speed: If you use PRs, treat them as high-priority items. A PR that sits for 24 hours is a PR that is likely to conflict with other changes.
Frequently Asked Questions
Is Trunk-Based Development only for senior developers?
Not at all. While TBD requires a certain level of discipline, it is actually a fantastic learning tool for junior developers. Because they are forced to break down their work and integrate frequently, they get much faster feedback on their code. They learn to write better, more modular code because the process demands it.
What if my company requires strict manual QA before release?
You can still practice TBD internally. The "trunk" becomes your internal development line, and you can create a "release branch" only when you are ready to ship. The key is that the release branch is created from the trunk, and you never merge from that release branch back to the trunk. Any fixes found during QA are applied to the trunk first and then cherry-picked into the release branch.
Does TBD mean we lose the ability to track features?
No. You track features through your project management tools (like Jira or Trello) and through your feature flags. The code itself becomes a reflection of the current state of the product, not a collection of long-lived "feature branches."
Can I use TBD with a monolithic repository?
Yes, TBD is actually highly recommended for large monoliths. In a large repo, the risk of merge conflicts is high; constant integration helps manage this risk by identifying conflicts as soon as they are created.
Best Practices Checklist
- Small Increments: Ensure every commit represents a small, logical unit of work.
- Automated Tests: Maintain a test suite that covers at least 80% of your business logic.
- Feature Flags: Use them to decouple deployment from release.
- Fast CI: Ensure that your build and test pipeline runs in under 10 minutes.
- No Long-Lived Branches: Delete all branches within 48 hours of creation.
- Communication: Use team channels to broadcast major refactoring plans.
- Green Build Culture: Treat broken builds as the highest-priority issue for the entire team.
Conclusion: Key Takeaways
Trunk-Based Development is more than a technical preference; it is a cultural commitment to speed, quality, and collaboration. By moving away from the safety of long-lived branches, you trade a false sense of security for a system that forces you to solve integration problems as they happen.
- Continuous Integration is Mandatory: TBD fails without a fast, reliable CI pipeline. You cannot integrate frequently if you do not have automated confidence in your code.
- Decomposition is a Skill: The ability to break large features into small, deployable chunks is the defining skill of a TBD practitioner. If you cannot break a task down, you are not ready for TBD.
- Feature Flags are Essential: They allow you to safely merge incomplete work into the trunk, enabling true continuous delivery without sacrificing the user experience.
- The Trunk is Sacred: The health of the main branch is a collective responsibility. A broken trunk is not just one developer’s problem; it is the team’s problem.
- Rebase and Pull Often: Frequent synchronization with the trunk is the only way to avoid the dreaded merge conflict. When in doubt, pull the latest changes.
- Focus on Small PRs: If you use code reviews, keep them small. This reduces cognitive load for reviewers and speeds up the integration process.
- Embrace the Change: Moving to TBD is a significant shift in workflow. Start small, perhaps with a single team or a single project, and iterate on your process as you learn what works for your specific environment.
By adopting these practices, you will find that your team spends significantly less time wrestling with Git and significantly more time delivering value to your users. The friction of the merge process will disappear, and you will gain the ability to deploy changes to your system with confidence, at any time.
Enjoying the courses?
Everything stays free. Pro shows fewer ads, doubles your daily points limit so you progress twice as fast, and lets you read each lesson on one page.
- ✓ Fewer advertisements
- ✓ 2× daily points limit
- ✓ Distraction-free lessons