Trunk-based Development

Method

Everyone merges into a single trunk at least once a day, and no branch is kept alive for long.

Why it exists

Branching per feature was the default for a long time. A line split off the trunk to work on separately is a branch, and everyone worked freely in their own and merged when finished. Nobody gets in anybody's way during the work, which looks safe.

The trouble arrived on merge day. Merge a branch worked on separately for three weeks and the trunk has moved 300 lines in the meantime. Two edits to the same place that can't be combined automatically is a merge conflict, and merging three weeks of changes produces twenty of them at once. It takes two days, and mistakes that delete somebody else's code slip in while resolving them. The conflicts are not the real cost either; the real cost is that nobody can tell whether the resolved version still does what both sides intended.

Whoever waited paid too. Three people each holding a three-week branch means three lumps merging in sequence, and the second person has to rebase after the first lands. The last person does it twice. With long branches that cost grows with the square of the team size.

Trunk-based development attacks the cost through branch lifetime. Remove long-lived branches and the amount that can diverge shrinks. Merge fifteen days' worth fifteen times instead of three weeks' worth once, and a single conflict is two lines.

How to run it

Everyone faces the same line and cuts work into pieces that merge inside a day. Five things to hold.

  1. Keep one trunk. The deployed code always lives on it and nobody stays away from it for long. Branches aren't banned — they're made and deleted inside a day.
  2. Merge at least once a day, finished or not. This is where it diverges most from the older way, and it means the way work gets cut has to change too. Learning to slice a three-week feature into fifteen day-sized pieces is the actual difficulty of this method. A piece that can't be finished in a day can usually still be merged in a day, because merging is not the same as finishing.
  3. Ship unfinished code switched off. A switch that turns a feature on and off while the code is already deployed is a feature flag, and a half-built screen goes onto the trunk with that switch off. Users have no such feature and the code is already merged. The flag also becomes the release control: turning it on later is a decision separate from deploying, and it can be turned off again without a rollback.
  4. Let a machine check every merge. Merging often and verifying automatically is continuous integration, and this method doesn't stand up without it. Nobody reviews the whole system by hand fifteen times a day.
  5. Keep review turnarounds short. A request to merge changes is a pull request, and here it stays under about 200 lines so it clears in hours. A two-day review breaks the once-a-day rule automatically. Review size is the lever people forget, and it governs the other four.

When it fits and when it doesn't

Three conditions favor it. The first is serving one product as one version, which describes most web services. The second is a team that already has automated checks running. The third is a team that deploys often — shipping several times a day makes merging daily natural, whereas on a monthly release the merged code waits a month and the changes pile back into one lump. None of the three is about tooling; all three are about how often the team is willing to be interrupted by a merge.

The limits are clear too. Supporting several versions at once can't be done with this alone. If a customer is on an older version and security fixes have to go out against it, there is no choice but keeping a line alive for that version. The usual compromise is running the trunk this way and keeping only the old versions on separate lines.

It also doesn't suit public projects with many outside contributors. You can't hand strangers permission to merge straight into the trunk, so a route through forking and review is required. Git flow, which runs separate branches per role, still earns its place there.

Adopting this before the checks exist produces the opposite result. A trunk merged into fifteen times a day with no checks accumulates broken code, and finding who broke it takes longer than before. The order is checks first, branch lifetime second. Teams that get this backwards usually conclude the method doesn't work, when what didn't work was the sequence.

How it sounds at work

"This branch is five days old. Please slice it so it can land today."

The lifetime is growing, so split the work.

"How do I merge an unfinished feature? Put it behind a flag."

Pointing at the mechanism for shipping incomplete code.

"The trunk is broken. Let's get checks in place before moving to this."

The order got reversed.

Pagedeck switched after Theo joined. Before that, feature branches averaged nine days and every merge day cost half a day of conflict resolution. Now branch lifetime averages 1.2 days and conflicts are usually one or two lines.

What held the migration up was not the branching but the slicing. Mia started writing requirements in day-sized pieces from the start, and that took about two months to settle. The tooling changed on day one; the habit did not. Anyone evaluating this method should budget for the second part rather than the first.

What people get wrong

The most common reading is that this is a method without branches. The name centers the trunk and the rule says to remove long-lived branches, so it sounds that way. In practice branches get used, with lifetimes held under a day. Drop them entirely and commit straight to the trunk and the place review happens disappears, and broken code lands before any check runs. Teams that read it as a ban on branches throw out review along with them, and trade the problem this method solves for a different one. Short-lived and absent are different states, and only one of them keeps review intact.

The other frequent view is that raising the merge frequency is the whole job. The rule says daily, so hitting daily looks sufficient. But what the method actually demands is the ability to cut work into day-sized pieces, and that has to change as far upstream as how requirements get written. Raise the count without the slicing practice and half-built code goes onto the trunk with no flag on it, and users see a screen that was never finished. Tooling settings change in a day; this habit takes a couple of months. Frequency is the visible half of the practice and the cheaper half to copy.

Where to go next

  • Version control

    see where the strategy branch sits in the whole

  • Git flow

    put the opposite convention beside it and the choice gets clearer

Related terms

Last updated 2026-09-16