TBD Migration Guide
A tactical guide for migrating from GitFlow or long-lived branches to trunk-based development, covering regulated environments, multi-team coordination, and common pitfalls.
10 minute read
Phase 1 - Foundations
Trunk-based development is the first foundation to establish. Without daily integration to a shared trunk, the rest of the CD migration cannot succeed. This page covers the core practice, two migration paths, and a tactical guide for getting started.
Trunk-based development (TBD) is a branching strategy where all developers integrate their work into a single shared branch - the trunk - at least once per day. The trunk is always kept in a releasable state.
This is a non-negotiable prerequisite for continuous delivery. If your team is not integrating to trunk daily, you are not doing CI, and you cannot do CD. There is no workaround.
“If it hurts, do it more often, and bring the pain forward.”
- Jez Humble, Continuous Delivery
main with no guardrails.” You still test, review, and validate work - you just do it in small increments.| Problem | How TBD Helps |
|---|---|
| Merge conflicts | Small changes integrated frequently rarely conflict |
| Integration risk | Bugs are caught within hours, not weeks |
| Long-lived branches diverge from reality | The trunk always reflects the current state of the codebase |
| “Works on my branch” syndrome | Everyone shares the same integration point |
| Slow feedback | CI runs on every integration, giving immediate signal |
| Large batch deployments | Small changes are individually deployable |
| Fear of deployment | Each change is small enough to reason about |
There are two valid approaches to trunk-based development. Both satisfy the minimum CD requirement of daily integration. Choose the one that fits your team’s current maturity and constraints.
Developers create branches that live for less than 24 hours. Work is done on the branch, reviewed quickly, and merged to trunk within a single day.
How it works:
Best for teams that:
Key constraint: The branch must merge to trunk within 24 hours. If it does not, you have a long-lived branch and you have lost the benefit of TBD.
Developers commit directly to trunk. Quality is ensured through pre-commit checks, pair programming, and strong automated testing.
How it works:
Best for teams that:
Key constraint: This requires excellent test coverage and a culture where the team owns quality collectively. Without these, direct trunk commits become reckless.
Ask these questions:
Both paths are valid. The important thing is daily integration to trunk. Do not spend weeks debating which path to use. Pick one, start today, and adjust.
Trunk-based development does not work in isolation. These supporting practices make daily integration safe and sustainable.
When you integrate to trunk daily, incomplete features will exist on trunk. Feature flags let you merge code that is not yet ready for users.
Rules for feature flags in TBD:
When NOT to use feature flags:
Feature flags are covered in more depth in Phase 3: Optimize.
The ability to make code changes that are not complete features and integrate them to trunk without breaking existing behavior is a core skill for trunk-based development. You never make big-bang changes. You make small changes that limit risk. Feature flags are one approach, but two other patterns are equally important.
Branch by abstraction lets you gradually replace existing behavior while continuously integrating to trunk. It works in four steps:
Each step is a separate commit that keeps trunk working. The old behavior runs until you explicitly switch, and you can remove the abstraction layer once the migration is complete.
Connect Last means you build all the components of a feature, each individually tested and integrated to trunk, and wire them into the user-visible path only in the final commit.
Because nothing references the new code until the last commit, there is no risk of breaking existing behavior during development.
| Pattern | Best for | Example |
|---|---|---|
| Connect Last | New features that do not affect existing code | Building a new checkout flow, adding a new report page |
| Branch by Abstraction | Replacing or modifying existing behavior | Swapping a payment processor, migrating a data layer |
| Feature Flags | Gradual rollout, testing in production, or customer-specific features | Dark launches, A/B tests, beta programs |
If your change does not touch existing code paths, Connect Last is the simplest option. If you are replacing something that already exists, Branch by Abstraction gives you a safe migration path. Reserve feature flags for cases where you need runtime control over who sees the change.
Each commit should be a small, coherent change that leaves trunk in a working state. If you are committing once a day in a large batch, you are not getting the benefit of TBD.
Guidelines:
TDD provides the safety net that makes frequent integration sustainable. When every change is accompanied by tests, you can integrate confidently.
Both practices ensure that your test suite grows with your code and that trunk remains releasable.
If your team currently uses long-lived feature branches, start by shortening their lifespan.
| Current State | Target |
|---|---|
| Branches live for weeks | Branches live for < 1 week |
| Merge once per sprint | Merge multiple times per week |
| Large merge conflicts are normal | Conflicts are rare and small |
Action: Set a team agreement that no branch lives longer than 2 days. Track branch age as a metric.
Tighten the window from 2 days to 1 day.
Action:
Daily integration is only useful if trunk remains in a releasable state.
Action:
Once the team is integrating daily with a green trunk, eliminate the option of long-lived branches.
Action:
If you are merging to trunk daily but also maintaining a long-lived feature branch, you are not doing TBD. The feature branch will diverge, and merging it later will be painful. The integration to trunk must be the only integration point.
If your CI pipeline takes 30 minutes, integrating multiple times a day feels impractical. This is a real constraint - address it by investing in build automation and parallelizing your test suite. Target a build time under 10 minutes.
Yes, you can. Use feature flags to hide incomplete work from users. The code exists on trunk, but the feature is not active. This is a standard practice at every company that practices CD.
If pull request reviews take 2 days, daily integration is impossible. The solution is to change how you review: pair programming provides continuous review, mob programming reviews in real time, and small changes can be reviewed asynchronously in minutes. See Code Review for specific techniques.
This is why you have automated tests, CI, and the “broken build = top priority” agreement. Bad commits will happen. The question is how fast you detect and fix them. With TBD and CI, the answer is minutes, not days.
Track these metrics to verify your TBD adoption:
| Metric | Target | Why It Matters |
|---|---|---|
| Integration frequency | At least 1 per developer per day | Confirms daily integration is happening |
| Branch age | < 24 hours | Catches long-lived branches |
| Build duration | < 10 minutes | Enables frequent integration without frustration |
| Merge conflict frequency | Decreasing over time | Confirms small changes reduce conflicts |
This page covers the essentials for Phase 1 of your migration. For detailed guidance on specific scenarios:
Once your team is integrating to trunk daily, build the test suite that makes that integration trustworthy. Continue to Testing Fundamentals.
A tactical guide for migrating from GitFlow or long-lived branches to trunk-based development, covering regulated environments, multi-team coordination, and common pitfalls.