Trunk-Based Development vs Gitflow: Which Branching Strategy to Use

Devops & Infrastructure and Git

Trunk-Based Development vs Gitflow: Which Branching Strategy to Use

Most engineering teams pick a branching strategy in their first month and live with it for years. It's rarely revisited — even when the team triples in size or merge conflicts start eating a full afternoon a week. Branching strategy is one of those decisions that quietly determines how fast you can ship.

Two patterns dominate the conversation: trunk-based development and Gitflow. They sit at almost opposite ends of the spectrum. This article gives the honest tradeoffs, says where each one actually fits, and takes a position on which most modern web teams should default to.


The two strategies in one paragraph each

Trunk-based development keeps a single long-lived branch — usually main — as the source of truth. Engineers either commit directly to it or use feature branches that live for a few hours to a day at most. Work that isn't ready to ship is hidden behind feature flags rather than parked on a branch. Continuous integration runs on every commit, and main is always considered releasable.

Gitflow is a structured branching model introduced by Vincent Driessen in 2010. It uses two long-lived branches (main for production, develop for ongoing integration) plus short-lived feature/*, release/*, and hotfix/* branches with strict merge rules. Releases are explicit events: you cut a release/* branch, stabilize it, tag it, and merge back. A generation of teams learned Git from that one diagram.


How trunk-based development actually works

The mechanics are simpler than the cultural shift required to make them work.

Engineers pull from main, do their work in small increments, and integrate back within hours. If a change is too big to land in a day, it's split — not parked on a long-lived branch. Short-lived feature branches are tolerated for code review and CI gating, but the goal is to keep them measured in hours, not weeks.

The hard part is what to do when work spans multiple commits and isn't ready for users. That's what feature flags are for. A new checkout flow can ship to production behind a flag set to false, get exercised by internal users with the flag on, and roll out to real customers gradually. The branch never has to hold the unfinished work. Our explainer on what feature flags are walks through the mechanics.

This style depends on a few things being non-negotiable:

  • Mandatory CI on every push. A broken main blocks everyone, so the build has to be defended fiercely.
  • Small pull requests. PRs that take more than a day to review are a smell, not a badge of honor.
  • Feature flags as a first-class concept. Not just for A/B tests — for everyday this isn't ready yet work.
  • Strong test coverage. When you don't have a stabilization branch, your tests have to do that job.

Google, Meta, and Netflix are the most-cited adopters at scale. The reason isn't that they invented something exotic — it's that they invested enormously in fast CI, ubiquitous flags, and sophisticated rollout tooling to make trunk-based safe with thousands of engineers committing to one branch.


How Gitflow actually works

Gitflow's appeal is structure. Every kind of change has a named branch and a defined lifecycle, and there's no ambiguity about where a fix belongs or how it gets to production.

Here's the lifecycle of a single feature under the original Gitflow specification:

  1. Branch from develop. You create feature/checkout-redesign off develop. All ongoing work happens here.
  2. Commit freely. Merge conflicts only show up when you come back to integrate.
  3. Merge into develop. When the feature is done, it's reviewed and merged into develop, joining everyone else's pending work.
  4. Cut a release branch. When the team decides to ship, someone creates release/1.7.0 from develop. Only bug fixes and release-prep commits land here — no new features.
  5. Stabilize and tag. QA happens on the release branch. When it's clean, it's merged into both main (tagged as the release) and back into develop (so the fixes aren't lost).
  6. Hotfix when production breaks. If a critical bug hits production, you branch hotfix/1.7.1 off main, fix it, tag it, and merge back into both main and develop.

The result is a Git history that looks like a parallel highway system. It's verbose, but it tells you exactly when each release happened and what's in it. For software that ships to specific dated releases — or has to be maintained across multiple supported versions at once — that structure is genuinely useful.


Head-to-head comparison

Dimension Trunk-based development Gitflow
Release cadence Multiple times per day Weekly, monthly, or longer
Long-lived branches One (main) Two (main + develop) plus rolling release/*
Typical branch lifespan Hours to one day Days to weeks
Merge complexity Low — small frequent merges High — periodic large merges
CI requirements Mandatory and fast Helpful but optional
Feature flag dependency Heavy reliance Optional
Solo / small team fit Excellent — almost no overhead Overkill
Large team fit Excellent with strong tooling Workable but slower
Parallel release lines Awkward (needs release branches off main) Native — that's what release/* and hotfix/* exist for
Rollback story Feature flag flip or revert + redeploy Re-deploy previous tagged release
Onboarding friction Low — one branch to understand Higher — five branch types and rules between them
History readability Cleaner linear main Verbose, but releases are explicit

The pattern that emerges: trunk-based optimizes for integration speed at the cost of requiring strong CI and flag discipline. Gitflow optimizes for release ceremony and parallel maintenance at the cost of slower integration and bigger merges.


When trunk-based wins

For most modern web teams, trunk-based is the right default. The conditions where it genuinely shines:

  • You run a SaaS product with continuous deploy. One production environment, no version 1.7 living in customer hands.
  • Your team has more than 5 engineers. Long-lived branches scale badly with team size — every additional branch is another integration point waiting to conflict. Trunk-based forces continuous integration, keeping the pain small and constant rather than large and periodic.
  • You have strong CI culture. A well-instrumented CI/CD pipeline is the safety net. Without it, trunk-based feels reckless.
  • Feature flags are available. Either a third-party platform or a homegrown system. Without flags, every in-progress change becomes a branch, and you've reinvented Gitflow accidentally.
  • You don't support multiple parallel versions. If the latest version is the only version, you don't need release branches.

The trunk-based bet is that integration cost compounds, and the cheapest way to keep it low is to never let it grow. Combined with continuous deployment and the right tooling, you can move from commit to running in production in minutes instead of weeks.


When Gitflow still makes sense

Gitflow gets unfairly dismissed in trunk-based advocacy. There are real contexts where it's the better answer:

  • Packaged or versioned software. Desktop apps, SDKs, mobile apps pushed through app stores, self-hosted products where customers run version 4.2 for years — all need explicit versioning. Gitflow's release/* and hotfix/* branches map directly onto that reality.
  • Scheduled release windows. Regulated industries — finance, healthcare, government — can't deploy whenever they feel like it. Releases are events with paperwork, scheduled windows, and signoff. The release branch is where that stabilization work lives.
  • Parallel maintenance branches. Supporting v3.x for security fixes while v4.x is the active line means long-lived branches per version. That's exactly what Gitflow's hotfix model handles.
  • Teams without robust CI. Trunk-based assumes a green main. If your test suite is slow, flaky, or incomplete, an integration branch (develop) absorbs the chaos before it reaches the release branch.
  • Heavy QA gates. If ready to merge and ready to ship are different states owned by different people, a release branch is a useful place to stage that handoff.

Several of those points are constraints you don't always get to choose — compliance and tooling maturity dictate the workflow as much as preference does. Pretending otherwise is how cargo-cult trunk-based adoption ends in tears.

Whichever model you pick, the deploy story matters as much as the branch story. DeployHQ deploys from any branch you point it atmain, develop, a stabilized release/*, whatever your team's workflow demands — without locking you into a specific Git workflow.


The middle ground: GitHub Flow and GitLab Flow

Most teams that call themselves trunk-based are actually running GitHub Flow or GitLab Flow — lighter-weight alternatives between the two extremes.

GitHub Flow is the simplest: there's main and short-lived feature branches merged via pull request. No develop, no release branches, no hotfix ceremony beyond branch from main, fix it, merge it, deploy. It works beautifully for SaaS products with continuous deploy and small-to-medium teams. The line between GitHub Flow and strict trunk-based is blurry — the main difference is that GitHub Flow expects every change to go through a PR, where strict trunk-based tolerates direct-to-main commits.

GitLab Flow adds environment-specific branches — typically staging and production — that act as deployment targets. Commits flow from main into staging, then production, mirroring the actual deploy pipeline. It's a pragmatic option if your release model is more nuanced than merge to main = ship to users but you don't want Gitflow's full complexity. Our comparison of GitLab and GitHub as platforms covers how each one handles these workflows natively.

For a broader survey — including Release Flow — see our overview of Git branching strategies.


Migrating from Gitflow to trunk-based

Most teams that switch try to do it overnight, declare bankruptcy on develop, and end up with three months of merge conflicts. There's a less painful sequence.

Step 1: Shorten branch lifespan before changing anything structural. Cap feature branches at three days, then two, then one. Force-rebase against develop daily. This alone surfaces most of the integration pain Gitflow hides, and gives the team practice resolving conflicts in small chunks.

Step 2: Introduce feature flags. Before you can kill develop, you need somewhere to hide unfinished work besides a branch. Pick a flag system — third-party or homegrown — and require new in-progress features to use it.

Step 3: Shrink the release window. Instead of cutting release/* days before shipping, cut it the morning of. The goal is to make develop look more and more like main.

Step 4: Stop using develop. Once features go to main via short-lived branches, and flags hide what's not ready, develop has nothing to do. Delete it.

Step 5: Switch release tags for release branches. Instead of release/1.7.0, tag main at the commit you shipped from. Hotfixes branch from the tag, merge to main, and ship. You're now running trunk-based with canary releases or whatever rollout pattern fits your risk tolerance.

The whole migration usually takes a quarter or two for a team of 5-20 engineers. Compressing it into a sprint is how teams give up halfway.


Deployment automation regardless of strategy

Branching strategy and deployment tooling are separate concerns, but they have to play well together. Trunk-based only matters if your deploy pipeline can ship continuously. Gitflow's release branches only earn their keep if releases are actually automated, not a manual SSH-and-rsync ordeal.

DeployHQ is branch-agnostic by design: you configure which branch deploys to which environment, and the pipeline takes it from there. Git deployment automation triggers on every push to your chosen branch — main for trunk-based, a release/* line for Gitflow, or both at once for staged rollouts. The walkthrough of how to deploy with Git on DeployHQ covers the web UI, the API, and the CI integration paths.

A few things matter for both strategies:

  • Rollback without a redeploy. When something goes wrong, one-click rollback restores the previous successful deployment in seconds. Trunk-based teams need it for fast recovery from a flag-less mistake; Gitflow teams need it when a tagged release turns out to be broken.
  • Direct repository integration. You can deploy directly from GitHub, GitLab, or Bitbucket — no intermediary CI step required. Useful for trunk-based teams who want commit-to-production with minimal pipeline glue.
  • Coexistence with existing CI. If you already run a custom pipeline — a GitHub Actions alternative approach with DeployHQ as the deploy step, or a hybrid of DeployHQ vs Jenkins where Jenkins handles tests — DeployHQ slots in cleanly as the deploy stage without forcing a particular Git workflow.

If you're not sure where deployment automation fits versus what your CI covers, the differences between continuous delivery and continuous deployment are usually the missing concept.


So which one should you pick?

For most modern web engineering teams shipping a SaaS product, start with trunk-based — or its lighter cousin, GitHub Flow. Integration cost stays low, the workflow scales with the team, and you deploy when you're ready instead of when the calendar says so.

Pick Gitflow when you have a real reason: versioned releases for customers, regulatory release windows, parallel maintenance lines, or an organization that can't justify investing in CI and flag tooling. Those are legitimate. We've always done it this way is not.

The worst outcome is the middle: nominally Gitflow, branches that live for weeks, no CI to catch the drift, no flags to land work safely. That setup gets the overhead of Gitflow and the bug surface of bad trunk-based without the benefits of either. If you're stuck there, the migration steps above are the way out.

Whichever model you pick, give DeployHQ a try for automated deployments — and stop letting branching strategy decide how often you can ship.


Questions, war stories, or want to argue about feature flags? Email us at support@deployhq.com or find us on Twitter at @deployhq.