Trunk-Based Development
Trunk-Based Development (TBD) is the practice of integrating code into a single shared branch — called trunk or main — as frequently as possible, ideally multiple times per day. Rather than waiting for a feature to be complete before merging, developers commit small increments directly to trunk. Incomplete features are hidden behind feature flags so they do not affect end users until deliberately enabled. TBD is the workflow behind the continuous integration practices of Google, Facebook, Netflix, and most elite software engineering organisations.
The core model
Trunk-Based Development topology
trunk (main):
A ── B ── C ── D ── E ── F ── G ── H ──▶
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
│ │ │ │ │ │ │ │
Alice Bob Bob Alice Bob Alice Alice Bob
(all committing small increments to trunk)
Short-lived branches (optional, < 1 day):
├── X ── Y ──┤ (Alice's tiny branch, merged same day)
Feature flags hide incomplete work:
Feature "new-checkout" exists in code on trunk
but is disabled in production via a config flag.
Only enabled when fully tested and ready.Two valid styles of TBD
Style | Description | Branch lifetime | Best for |
|---|---|---|---|
Direct to trunk | Commit directly to main, no branches | N/A | Senior teams with strong CI/CD |
Short-lived branches | Create a branch, merge within hours or 1 day max | < 1 day | Teams that prefer a PR review step |
Feature flags: the key enabler
Feature flags (also called feature toggles) allow you to ship code that is not yet ready for users. The code lives in trunk and is continuously integrated, but a configuration switch keeps it invisible to end users until you decide to enable it. This decouples deployment (pushing code to production) from release (making a feature available to users).
Concept: feature flag in code
# Feature flag stored in environment config or a feature flag service
# (LaunchDarkly, Unleash, Flagsmith, etc.)
# In your code:
# if (featureFlags.isEnabled('new-checkout-flow')) {
# return <NewCheckout />;
# }
# return <LegacyCheckout />;
# Developer commits the new-checkout code to trunk
# with the flag OFF (disabled for all users).
git add src/checkout/
git commit -m "feat: add new checkout flow [flag: new-checkout-flow=off]"
git push origin main
# CI/CD deploys to production — users see legacy checkout
# QA team enables the flag for the staging environment to test
# When ready: enable the flag for 1% of users → 10% → 100%Simple feature flag implementation
# features.ts — a simple flag store
export const flags = {
newCheckoutFlow: process.env.FEATURE_NEW_CHECKOUT === 'true',
darkMode: process.env.FEATURE_DARK_MODE === 'true',
betaSearch: process.env.FEATURE_BETA_SEARCH === 'true',
}
# In component:
# import { flags } from './features'
# const Checkout = flags.newCheckoutFlow ? NewCheckout : LegacyCheckout
# Environment variable in CI/CD pipeline (off by default):
# FEATURE_NEW_CHECKOUT=false ← production
# FEATURE_NEW_CHECKOUT=true ← staging / QADay-to-day workflow
TBD daily workflow (direct to trunk)
# Start of day: get latest trunk git pull origin main # Make a small, focused change vim src/api/user.ts # (write code, keep the change minimal — under 200 lines ideally) # Run tests locally BEFORE committing npm test npm run lint # Stage and commit git add src/api/user.ts tests/user.test.ts git commit -m "feat: add email verification to user registration" # Pull again (someone may have pushed while you were coding) git pull --rebase origin main # Push immediately git push origin main
TBD with short-lived branches (< 1 day)
# Create a branch (must be merged SAME DAY) git switch -c feat/email-verification # (< 1 day of work — keep it tiny) git commit -m "feat: add email verification to user registration" git push -u origin feat/email-verification # Open PR for quick review gh pr create --title "Add email verification" --body "..." # (get approval within hours, not days) # Merge gh pr merge --squash --delete-branch git switch main git pull origin main
Continuous integration requirements
TBD only works safely when your CI pipeline is fast and reliable. Every commit to trunk must be automatically verified before anyone else can break on it.
Required CI pipeline for TBD
Every commit to main triggers: 1. Dependency installation (< 30 seconds) 2. Unit tests (< 5 minutes) 3. Integration tests (< 10 minutes) 4. Static analysis / linting (< 2 minutes) 5. Build (< 5 minutes) 6. Deployment to staging (< 5 minutes) 7. Smoke tests on staging (< 2 minutes) Total: ideally under 15 minutes. If CI takes > 30 minutes, TBD becomes painful.
Benefits of Trunk-Based Development
No merge hell — because everyone integrates continuously, large diverging branches never accumulate. Conflicts are tiny and resolved immediately.
True continuous integration — CI really runs on the integrated code, not just on isolated branches. You catch integration bugs immediately.
Fast feedback — developers know within minutes if their change broke something.
Smaller code reviews — changes are tiny (single commits or tiny PRs), making reviews faster and more thorough.
Simpler branching model — no develop, no release branches, no hotfix branches. One branch, one source of truth.
Deployments are boring — because each commit is small and verified, deployments carry minimal risk.
Lower WIP limit — fewer works-in-progress means less context switching and faster flow.
Challenges and prerequisites
Fast test suite required — if tests take 40 minutes, no one will run them locally before pushing.
High test coverage required — bugs hidden by feature flags still land in production code. Tests must catch them.
Team discipline required — everyone must commit small, self-contained increments. Large changes need to be broken down.
Feature flag infrastructure required — for any feature that takes more than a day to build.
Strong code review culture — even without formal PRs, code quality must be maintained through other means (pair programming, post-commit review).
TBD vs feature branch workflows
Dimension | Trunk-Based | Feature Branch |
|---|---|---|
Branch lifetime | Hours or none | Days to weeks |
Merge frequency | Multiple times per day | When feature is complete |
Integration testing | Continuous on trunk | At PR review time |
Merge conflicts | Rare (tiny, frequent merges) | Common (large, infrequent merges) |
Feature isolation | Feature flags | Separate branches |
Code review | Post-commit or tiny PRs | Pre-merge via PR |
Required discipline | Very high | Moderate |
Required CI/CD | Excellent | Good |
Used by | Google, Facebook, Netflix | Most teams |
Who uses Trunk-Based Development
Google — tens of thousands of engineers commit to a single monorepo trunk. This is perhaps the largest TBD implementation in the world.
Facebook/Meta — similar monorepo approach with sophisticated automated testing and feature flags.
Netflix — TBD with extensive CI/CD and canary deployments.
Etsy — famously championed continuous deployment from a shared trunk.
High-performing DevOps organisations — DORA research consistently finds that elite performers use trunk-based development.