Lesson 112 of 12120 min read

Trunk-Based Development: Everyone Commits to main Frequently, Feature Flags

Learn Trunk-Based Development, the most branch-averse strategy of all, where developers integrate directly to main constantly and use feature flags instead of long branches.

Author: CodersNexus

Trunk-Based Development: Everyone Commits to main Frequently, Feature Flags

If GitHub Flow already felt like a significant simplification of Git Flow, Trunk-Based Development pushes even further in the same direction: developers integrate directly into a single shared branch extremely frequently — often multiple times a day — with even feature branches, when used at all, living for mere hours rather than days. This lesson explains the mechanism that makes this aggressive approach viable: feature flags.

Learning Objectives

  • Explain the core Trunk-Based Development practice of frequent, direct integration to a shared trunk.
  • Understand why extremely short-lived branches (or no branches at all) minimize merge conflict risk.
  • Explain what a feature flag is and how it enables shipping incomplete work safely.
  • Compare Trunk-Based Development's philosophy against GitHub Flow's pull-request-centric model.

Key Terms to Know Before Learning Trunk-Based Development

  • Trunk-Based Development: A branching strategy where developers integrate their work into a single shared branch (the 'trunk', typically main) extremely frequently, using very short-lived branches or committing directly.
  • Trunk: The single, shared branch (conventionally main) that all developers integrate their work into constantly in this strategy.
  • Feature flag (feature toggle): A configuration mechanism that lets incomplete or unreleased functionality exist in the codebase, deployed to production, but remain hidden or disabled until explicitly turned on.
  • Continuous integration: The practice of merging code changes into a shared branch very frequently, directly connecting to this strategy's core philosophy.

How Trunk-Based Development Actually Works

**Trunk-Based Development** takes the philosophy of minimizing branch divergence — a theme running throughout this entire course, from Module 3's branch lifespan lesson through GitHub Flow's simplification — to its logical extreme: developers integrate their work into a single shared branch (the **trunk**, conventionally `main`) **extremely frequently**, often multiple times per day. Branches, when used at all, are typically extremely short-lived — living for **hours**, not days — sometimes so short that some teams practicing 'pure' Trunk-Based Development skip branches entirely, with developers committing directly to the trunk.

The direct motivation connects straight back to Module 3's core insight about conflict risk: **the longer a branch diverges from the trunk while both continue changing, the higher the risk of a large, painful conflict.** Trunk-Based Development takes this to its natural conclusion — if divergence is the fundamental cause of conflict pain, then minimizing divergence to nearly zero (by integrating almost continuously) minimizes conflict pain to nearly zero as well, as a direct, mechanical consequence.

But this immediately raises an obvious question: how can you commit **incomplete, unfinished work** directly to the trunk multiple times a day, when the trunk (much like GitHub Flow's `main`) is generally expected to remain in a deployable state? This is exactly the problem **feature flags** (also called feature toggles) solve. A feature flag is a configuration mechanism — often as simple as a boolean check in code, or a more sophisticated remote-configurable system — that lets code for a new, unfinished feature exist in the codebase, and even be deployed all the way to production, while remaining **hidden or disabled** until it's explicitly, deliberately turned on:

```
if (featureFlags.isEnabled('new-checkout-flow')) {
renderNewCheckoutFlow();
} else {
renderOldCheckoutFlow();
}
```

This decouples two things that other strategies conflate: **deploying** code (getting it onto production servers) and **releasing** a feature (actually making it visible/active for users). A developer can commit and deploy genuinely incomplete work behind a disabled flag, continuing to build on it incrementally over days or weeks, all while the trunk itself remains technically deployable at every single point — the incomplete feature simply isn't *active* yet. Once the feature is actually complete, flipping the flag (often without even needing a new deployment, if the flag system is remotely configurable) makes it live for users, entirely independent of whatever commit originally introduced the code.

This strategy demands strong supporting practices to work well: a robust, fast **automated test suite** (since there's no long review/stabilization window before code reaches the trunk, catching problems requires strong automated safety nets, connecting to Module 8's practical hooks lesson on running tests) and genuine team discipline around **very small, incremental commits**. In exchange, teams practicing it well report minimal merge conflict pain (Module 3's core problem, essentially engineered away by never letting divergence accumulate) and extremely fast integration cycles — making it a natural fit for teams already practicing aggressive continuous deployment, often even more so than GitHub Flow.

Trunk-Based Development Workflow: Visual Walkthrough

Draw a single trunk line labeled 'main / trunk' with MANY small commit dots packed closely together along its length (far more frequent than the GitHub Flow diagram's few, larger merges), each labeled with tiny tick marks representing individual developers committing directly or via very short (hours-long) branches. Overlay a separate 'Feature Flag' toggle icon next to several commits, showing 'new-checkout-flow: OFF' for most of them, then flipping to 'new-checkout-flow: ON' at one specific later point — captioned 'Code for the incomplete feature is already deployed, just hidden behind the flag, until it's ready.'

Trunk-Based Development vs GitHub Flow: Key Differences

AspectGitHub FlowTrunk-Based Development
Branch lifespanDays (until a feature/PR is complete)Hours, or no branch at all — direct commits to trunk
Integration frequencyOnce per completed feature/PRMultiple times per day, per developer
How incomplete work stays hiddenKept on an unmerged branch until completeMerged/committed immediately, hidden behind a feature flag
Key supporting practice requiredCode review via pull requestsRobust automated testing + disciplined small commits

Trunk-Based Development: Command Syntax and Feature Flag Example

# Trunk-Based Development: frequent, small, direct integration
git switch main
git pull
# ... make a SMALL, incremental piece of progress on a new feature ...
git add .
git commit -m "feat: add checkout flow backend logic (behind feature flag)"
git push   # committing directly to main, or via a branch alive for only hours

# The new logic is guarded by a feature flag in the actual code:
# if (featureFlags.isEnabled('new-checkout-flow')) {
#   return newCheckoutHandler(request);
# } else {
#   return oldCheckoutHandler(request);
# }

# ... repeat this small-commit cycle many times over several days,
#     the trunk remains deployable throughout, since the flag stays OFF ...

# Once the feature is fully complete and tested, flip the flag (often remotely,
# without needing a new deployment at all):
# featureFlags.setEnabled('new-checkout-flow', true)

Breaking Down the Trunk-Based Development Example

This sequence demonstrates the rapid, small-commit cadence central to Trunk-Based Development — each commit represents a small, incremental step, integrated into the trunk almost immediately rather than accumulating on a long-lived branch. The feature flag code snippet shows the actual mechanism making this safe: the new checkout logic exists in the deployed codebase from a very early point, but remains entirely inactive (the `else` branch continues to run for real users) until the flag is explicitly flipped once the feature is genuinely complete — decoupling the act of deploying code from the act of releasing a feature to actual users.

How Trunk-Based Development Is Used on Real Engineering Teams

  • Large technology companies with very high deployment frequency (some deploying to production dozens or hundreds of times per day) are the most prominent, well-documented practitioners of Trunk-Based Development, since their scale and deployment cadence make long-lived branches genuinely impractical.
  • Feature flag management has become substantial enough as a practice that dedicated third-party services and platforms exist specifically to manage flags at scale, beyond what a simple boolean check in code can practically support for large teams.
  • A/B testing and gradual, staged feature rollouts (enabling a flag for only a percentage of users first) are common extensions of the basic feature flag concept, letting teams validate a new feature's real-world impact before fully committing to it for everyone.
  • Teams adopting Trunk-Based Development often invest heavily in improving their automated test suite's speed and reliability first, recognizing that this supporting infrastructure is a genuine prerequisite for the strategy to work safely, not an optional nice-to-have.

Trunk-Based Development Interview Questions and Answers

Q1. What is the core practice of Trunk-Based Development, and what problem is it directly trying to minimize?

Developers integrate their work into a single shared trunk branch extremely frequently, often multiple times a day, using very short-lived branches (hours, not days) or committing directly. This directly minimizes merge conflict risk, since conflicts arise from divergence between branches, and Trunk-Based Development keeps that divergence as close to zero as possible by integrating almost continuously.

Q2. What is a feature flag, and what problem does it solve for Trunk-Based Development?

A feature flag is a configuration mechanism that lets code for a new, unfinished feature exist and even be deployed to production while remaining hidden or disabled until explicitly turned on. It solves the problem of committing genuinely incomplete work directly to a trunk that's expected to remain deployable, by decoupling deploying code from releasing a feature to actual users.

Q3. What supporting practices does Trunk-Based Development require to work well, and why?

A robust, fast automated test suite is essential, since there's no long review or stabilization window before code reaches the shared trunk, meaning automated tests are the primary safety net catching problems. Genuine team discipline around making very small, incremental commits is also required, since large, infrequent commits would undermine the strategy's core goal of minimizing divergence.

Trunk-Based Development Quiz: Test Your Understanding

1. What is the core practice of Trunk-Based Development?

  1. Maintaining long-lived feature branches for months
  2. Integrating work into a single shared trunk branch extremely frequently, often multiple times a day
  3. Never committing directly to any shared branch
  4. Requiring a separate release branch for every feature

Answer: B. Integrating work into a single shared trunk branch extremely frequently, often multiple times a day

Explanation: Trunk-Based Development is defined by this very frequent integration cadence, using extremely short-lived branches or direct commits, minimizing divergence and therefore conflict risk.

2. What is a feature flag used for in Trunk-Based Development?

  1. Marking a branch as ready for deletion
  2. Letting incomplete code exist in the deployed codebase while remaining hidden or disabled until explicitly enabled
  3. Automatically resolving merge conflicts
  4. Tagging a specific release version

Answer: B. Letting incomplete code exist in the deployed codebase while remaining hidden or disabled until explicitly enabled

Explanation: A feature flag decouples deploying code from releasing a feature to users, letting incomplete work be committed and even deployed safely while remaining inactive until it's genuinely ready.

3. Why does Trunk-Based Development require a robust, fast automated test suite?

  1. Because it has no other purpose
  2. Because there's no long review or stabilization window before code reaches the shared trunk, so automated tests are the primary safety net
  3. Because feature flags automatically require it by design
  4. Testing is not actually required for Trunk-Based Development

Answer: B. Because there's no long review or stabilization window before code reaches the shared trunk, so automated tests are the primary safety net

Explanation: Since code integrates into the trunk almost immediately, without an extended review or stabilization phase, a strong automated test suite becomes essential for catching problems that a longer-lived branch or more extensive review process might otherwise catch.

Common Mistakes When Adopting Trunk-Based Development

  • Adopting Trunk-Based Development's frequent integration cadence without first investing in the robust automated testing it genuinely depends on to work safely.
  • Using feature flags but never actually removing them once a feature is fully released, letting stale, unused flags accumulate and clutter the codebase over time.
  • Committing large, infrequent changes directly to the trunk, undermining the strategy's core goal of minimizing divergence through small, frequent integration.
  • Assuming Trunk-Based Development means no code review or quality process at all, rather than understanding it shifts more of that responsibility onto automated testing and very small, easily reviewable changes.

Trunk-Based Development: Exam-Ready Quick Notes

  • Trunk-Based Development: extremely frequent integration (often multiple times/day) into a single shared trunk, minimizing divergence and conflict risk.
  • Branches, if used, are extremely short-lived (hours); some teams commit directly to the trunk.
  • Feature flags: let incomplete code exist in production while remaining hidden/disabled, decoupling deploy from release.
  • Requires strong supporting practices: robust automated testing, disciplined small commits.

Trunk-Based Development: Key Takeaways

  • Trunk-Based Development takes Module 3's short-branch-lifespan principle to its logical extreme, minimizing divergence almost to zero through extremely frequent integration.
  • Feature flags are the key enabling mechanism, letting incomplete work be safely committed and even deployed while remaining hidden from actual users.
  • This strategy genuinely depends on strong supporting practices — robust automated testing and small, disciplined commits — to work safely without a traditional long review window.

Frequently Asked Questions About Trunk-Based Development

Q1. What is Trunk-Based Development?

It's a branching strategy where developers integrate their work into a single shared trunk branch (usually main) extremely frequently, often multiple times a day, using very short-lived branches or committing directly, specifically to minimize the merge conflicts that arise from branches diverging over time.

Q2. What is a feature flag, and why is it essential to Trunk-Based Development?

A feature flag is a configuration toggle that lets new, unfinished code exist in the deployed codebase while remaining hidden or inactive until explicitly enabled. It's essential because it lets developers commit and deploy genuinely incomplete work directly to the trunk without exposing it to real users, keeping the trunk technically deployable at all times.

Q3. Why does Trunk-Based Development need such a strong automated test suite?

Because code integrates into the shared trunk almost immediately, without an extended review or stabilization window that other strategies (like Git Flow's release branches) provide. Automated tests become the primary safety net for catching problems before they reach the trunk.

Q4. How is Trunk-Based Development different from GitHub Flow?

GitHub Flow still uses feature branches that live for the duration of a pull request review, typically days. Trunk-Based Development pushes integration much faster, with branches (if used at all) living only hours, relying on feature flags to hide incomplete work rather than keeping it on an unmerged branch.

Q5. Is Trunk-Based Development suitable for every team?

It works best for teams that have invested in robust, fast automated testing and genuine discipline around small, incremental commits. Teams without these supporting practices in place may find the strategy risky to adopt without first building that foundation.

Summary

Trunk-Based Development takes the principle of minimizing branch divergence to its logical extreme: developers integrate their work into a single shared trunk branch (conventionally `main`) extremely frequently, often multiple times a day, using branches that live for mere hours (if used at all) rather than days. This directly minimizes merge conflict risk, since conflicts arise from divergence, and near-continuous integration keeps that divergence close to zero. The key enabling mechanism is the feature flag — a configuration toggle letting code for an incomplete feature exist in the deployed codebase while remaining hidden or disabled until explicitly turned on, decoupling the act of deploying code from the act of releasing a feature to actual users. This strategy genuinely depends on strong supporting practices to work safely: a robust, fast automated test suite (since there's no extended review window before code reaches the shared trunk) and disciplined, very small, incremental commits. In exchange, teams practicing it well achieve minimal merge conflict pain and extremely fast integration cycles, making it a natural fit for organizations already practicing aggressive, high-frequency continuous deployment.

Frequently Asked Questions

It's a branching strategy where developers integrate their work into a single shared trunk branch (usually main) extremely frequently, often multiple times a day, using very short-lived branches or committing directly, specifically to minimize the merge conflicts that arise from branches diverging over time.

A feature flag is a configuration toggle that lets new, unfinished code exist in the deployed codebase while remaining hidden or inactive until explicitly enabled. It's essential because it lets developers commit and deploy genuinely incomplete work directly to the trunk without exposing it to real users, keeping the trunk technically deployable at all times.

Because code integrates into the shared trunk almost immediately, without an extended review or stabilization window that other strategies (like Git Flow's release branches) provide. Automated tests become the primary safety net for catching problems before they reach the trunk.

GitHub Flow still uses feature branches that live for the duration of a pull request review, typically days. Trunk-Based Development pushes integration much faster, with branches (if used at all) living only hours, relying on feature flags to hide incomplete work rather than keeping it on an unmerged branch.

It works best for teams that have invested in robust, fast automated testing and genuine discipline around small, incremental commits. Teams without these supporting practices in place may find the strategy risky to adopt without first building that foundation.