Technology·13 min read

Trunk-Based Development vs Gitflow: Which Fits Your Startup?

Your branching strategy quietly shapes how fast you ship, how often things break, and how painful onboarding feels. Most startups pick Gitflow by default and regret it within six months.

Nate Laquis

Nate Laquis

Founder & CEO

Your Branching Strategy Is a Product Decision

Most founders do not spend much time thinking about how their developers use Git. They think about the product roadmap, the hiring pipeline, the burn rate. But your branching strategy is one of those invisible infrastructure choices that shapes everything downstream: how fast features ship, how painful code reviews feel, how frequently production breaks, and how quickly a new hire can start contributing real code.

The two dominant approaches are Gitflow and trunk-based development. Gitflow was introduced by Vincent Driessen in 2010 and quickly became the industry standard. It defines a rigid branch hierarchy with dedicated branches for features, releases, hotfixes, and development. Trunk-based development, by contrast, has the entire team committing to a single main branch (the "trunk"), with short-lived branches that last hours, not days or weeks.

For a long time, Gitflow was the "professional" choice. But over the past five years, a clear pattern has emerged: high-performing engineering teams, from Google to Shopify to small YC startups, have moved to trunk-based development. The 2023 DORA report from Google found that trunk-based development is one of the strongest predictors of elite software delivery performance. Teams using it deploy 973 times more frequently than low performers and recover from incidents 6,570 times faster.

Developer laptop showing Git branch workflow and code editor with version control

This is not an abstract debate. The wrong branching strategy will cost your startup weeks of engineering time per quarter in merge conflicts, broken releases, and coordination overhead. Let's break down how each one actually works, where they shine, and which one you should pick.

How Gitflow Actually Works

Gitflow defines five types of branches, each with a specific purpose and lifecycle. Understanding the full picture is important because most teams that "use Gitflow" actually use a broken subset of it, which creates the worst of both worlds.

The Branch Structure

The main branch (sometimes called master) represents production code. Every commit on main is a release that has been deployed to production. The develop branch is the integration branch where features come together. It always reflects the latest delivered development changes for the next release.

When a developer starts working on a feature, they create a feature branch off of develop. The naming convention is typically feature/user-authentication or feature/JIRA-1234-payment-flow. The developer works on this branch for days or weeks, then opens a pull request back into develop. After code review and approval, the feature branch merges into develop and gets deleted.

When the team decides it is time to cut a release, they create a release branch off of develop. The naming convention is release/2.1.0. Only bug fixes, documentation, and release-oriented changes go into the release branch. No new features. When the release is ready, it merges into both main (triggering a production deployment) and back into develop (so the fixes are not lost). The merge into main gets tagged with the version number.

If a critical bug appears in production, the team creates a hotfix branch off of main, fixes the issue, then merges the hotfix into both main and develop. This ensures the fix reaches production immediately and also lands in the next development cycle.

Where Gitflow Gets Painful

The theory is clean. The practice is brutal for small teams. Here is what actually happens: a developer creates a feature branch on Monday. By Thursday, three other developers have merged their own feature branches into develop. The feature branch is now four days stale. The developer tries to merge and hits 15 merge conflicts across 8 files. They spend half a day resolving conflicts, introduce a subtle regression in the process, and the bug does not surface until staging two weeks later.

Long-lived feature branches are the core problem. The longer a branch lives, the more it diverges from the codebase everyone else is working on. Merge difficulty grows exponentially with branch lifetime, not linearly. A branch that lives for one day has trivial merges. A branch that lives for two weeks can require a full day of conflict resolution. Gitflow's design encourages exactly this pattern by giving feature branches first-class status with no urgency to merge them.

The release branch ceremony adds overhead too. Someone has to manage the release branch, coordinate which fixes go into it, ensure the dual merge back into main and develop happens correctly, and tag the release. For a three-person startup shipping a SaaS product, this is pure waste. You are not shipping boxed software. You are deploying a web application that should go live the moment the code is ready.

How Trunk-Based Development Works

Trunk-based development is radically simpler. There is one branch that matters: main (the trunk). Every developer on the team integrates their work into main at least once per day. That is the entire model.

The Workflow in Practice

A developer picks up a task. They pull the latest main, create a short-lived branch (sometimes called a "topic branch"), and start working. The branch name is descriptive but not ceremonial: add-stripe-webhook-handler or fix-signup-validation. The key constraint is that this branch should merge back into main within 24 hours. Ideally within a few hours.

When the work is ready (or a meaningful slice of it is ready), the developer opens a pull request against main. A teammate reviews it. The CI pipeline runs automated tests. If everything passes, the PR merges into main. The branch is deleted. Main is always in a deployable state.

For larger teams (20+ developers), some organizations skip the short-lived branch entirely and commit directly to main. Google famously operates this way with a monorepo that has over 86,000 engineers committing to a single trunk. Most startups do not need to go that far. Short-lived branches with pull requests give you code review without sacrificing integration speed.

Software development team collaborating on code review and branching strategy at shared workspace

The 24-Hour Rule

The 24-hour constraint is not arbitrary. It is the mechanism that prevents trunk-based development from devolving into chaos. When branches live for less than a day, merge conflicts are rare because the code has not had time to diverge significantly. Code reviews are fast because the diff is small, typically under 200 lines. And integration issues surface immediately, when the context is fresh and the fix is cheap.

This means you need to break large features into small, independently shippable slices. A feature like "add Stripe subscription management" is not one branch. It is five or six branches over three days: add the Stripe SDK and config, create the subscription data model, build the checkout API endpoint, wire up the webhook handler, add the frontend billing page, connect the cancellation flow. Each slice is small, testable, and safe to merge on its own.

If you are coming from Gitflow, this decomposition skill is the hardest part of the transition. It is also the most valuable. Teams that learn to break work into small, independently deployable pieces ship faster regardless of what branching strategy they use.

Feature Flags: The Key to Trunk-Based Development

The immediate objection to trunk-based development is always the same: "But what about features that take two weeks to build? I can't merge half-finished UI into production." This is a valid concern, and the answer is feature flags.

A feature flag is a conditional in your code that determines whether a feature is visible to users. The simplest version is an environment variable: ENABLE_NEW_BILLING_PAGE=false in production, true in staging. The sophisticated version is a feature flag service like LaunchDarkly, Statsig, or the open-source Unleash that lets you toggle features per user, per team, per percentage of traffic, all without deploying new code.

How Feature Flags Replace Feature Branches

Consider the scenario: you are building a completely new dashboard that will take three sprints to complete. In Gitflow, you would create a feature/new-dashboard branch and work on it for six weeks. In trunk-based development, you wrap the new dashboard behind a feature flag on day one.

Every commit merges to main. The new dashboard code is in production from the first day, but no user sees it because the flag is off. Your team can access it in production by enabling the flag for internal accounts. QA can test it in the real production environment with real data. When the dashboard is complete, you flip the flag. No big-bang merge. No release branch. No merge conflicts. Just a configuration change.

Feature flags also give you something Gitflow never can: gradual rollouts. You can enable the new dashboard for 5% of users, monitor error rates and performance metrics, then ramp to 25%, then 50%, then 100%. If something breaks at 25%, you flip the flag back to off. The rollback is instant, no deployment required. Compare that to reverting a Gitflow release branch merge that touched 47 files.

Practical Feature Flag Setup

For an early-stage startup, you do not need LaunchDarkly on day one. Start with a simple approach: a JSON config file or database table that maps flag names to boolean values, with an admin endpoint to toggle them. This takes half a day to build and covers 90% of use cases.

When you need percentage-based rollouts, user targeting, or A/B testing, move to a managed service. LaunchDarkly is the market leader but expensive at $10 per seat per month. Statsig has a generous free tier and doubles as an experimentation platform. Unleash is open source and self-hostable if you want to avoid another SaaS bill. PostHog also includes feature flags in their analytics platform, which is a smart bundle if you are already using them for product analytics.

The discipline that makes feature flags work is cleanup. Every flag should have an expiration date. When a feature is fully rolled out and stable, remove the flag and the conditional code. A codebase with 200 stale feature flags is its own kind of mess. Set a rule: flags older than 30 days after full rollout get deleted in the next sprint. If you are running organized sprints, add flag cleanup as a recurring task.

CI/CD Requirements and Merge Queue Strategies

Trunk-based development is only safe if your CI/CD pipeline is fast and reliable. When every developer is merging to main multiple times per day, a slow or flaky pipeline becomes a team-wide bottleneck. This is the prerequisite that most guides gloss over, and it is the reason some teams try trunk-based development and give up.

Pipeline Speed Targets

Your CI pipeline (from push to green check) should complete in under 10 minutes. Under 5 minutes is excellent. Over 15 minutes and developers start batching their changes into larger PRs to avoid waiting, which defeats the purpose of short-lived branches. If your test suite takes 20 minutes, you need to parallelize it, split it into fast and slow tiers, or invest in faster CI runners. GitHub Actions larger runners, CircleCI's performance plans, or self-hosted runners on beefy machines can cut build times dramatically.

Flaky tests are the other killer. A test that fails randomly 5% of the time means that with 20 merges per day, you get one false failure every day. Developers start ignoring red builds. Once that happens, your pipeline is just decoration. Fix or delete flaky tests immediately. There is no middle ground. If you need a deeper walkthrough on building a reliable pipeline, our CI/CD setup guide covers the full architecture.

Merge Queues

When multiple developers are merging to main throughout the day, you can hit a race condition: two PRs pass CI independently, but when both merge, the combination breaks main. This is called a "semantic conflict," and it happens more often than you would expect in a fast-moving codebase.

A merge queue solves this by serializing merges. When a PR is approved, it enters a queue instead of merging immediately. The queue rebases the PR on top of the latest main (including any PRs that merged ahead of it), runs CI again, and only merges if this rebased version passes. GitHub has a native merge queue feature (under repository settings > branch protection rules). GitLab calls it "merge trains." Both work well.

For teams of 2 to 5 developers, a merge queue is optional. Semantic conflicts are rare enough that fixing them manually is acceptable. For teams of 6 or more all committing to the same repository, a merge queue prevents a class of broken-main incidents that would otherwise erode trust in the process.

Branch Protection Rules

Regardless of team size, configure branch protection on main: require at least one approving review, require CI to pass before merging, prevent force pushes, and require branches to be up to date before merging. These are table stakes for trunk-based development. Without them, someone will merge a broken commit directly to main at 5 PM on a Friday, and you will spend your weekend debugging it.

Kanban board showing development workflow with task cards for sprint planning and release management

Release Management in Trunk-Based Development

One of the most common misconceptions about trunk-based development is that it means "every commit goes straight to production." That can be true, and some teams practice continuous deployment exactly this way. But it is not required. Trunk-based development is about integration strategy (everyone commits to one branch), not deployment strategy (how and when code reaches production).

Option 1: Continuous Deployment

Every merge to main triggers an automatic deployment to production. This is the simplest model and works well for SaaS products with good monitoring, feature flags, and fast rollback capabilities. Shopify, GitHub, and Netflix all operate this way. If your CI pipeline is solid and you have feature flags controlling unfinished work, continuous deployment is the end state you should aim for.

Option 2: Release Tags

Main is always deployable, but you choose when to deploy by tagging a commit. When you are ready to release, you tag the current HEAD of main with a version number: v2.4.0. Your CI pipeline detects the tag and triggers a production deployment. This gives you explicit control over release timing while keeping the single-branch workflow. It is a good middle ground for teams that are not yet confident in continuous deployment or that need to coordinate releases with marketing, sales, or customer communication.

Option 3: Release Branches for Hotfixes

Even in trunk-based development, there are situations where a release branch makes sense, specifically for hotfixes against an older release. If you deploy v2.4.0 on Monday and then merge three more PRs into main by Wednesday, but a critical bug is found in production, you do not want to deploy main (which now contains untested changes). Instead, you create a branch from the v2.4.0 tag, cherry-pick the fix, and deploy that branch. Once the fix is verified, you merge it back into main.

This is the only scenario where a branch other than main should live for more than a day. It is not a permanent branch. It is a short-lived escape hatch for emergencies. If you find yourself creating release branches regularly, it is a sign that your CI/CD pipeline or test coverage needs work, because main should always be safe to deploy.

Versioning Strategy

For SaaS products deployed as web applications, semantic versioning (major.minor.patch) is optional. Many teams use date-based versions (2027.11.23.1) or simply reference the Git commit SHA. Semantic versioning becomes important if you ship libraries, APIs with external consumers, or mobile apps where multiple versions coexist in the wild. Pick a scheme and be consistent; the specific format matters less than the team's ability to trace any production deployment back to an exact commit.

When Gitflow Still Makes Sense

I have been making the case for trunk-based development, but I want to be honest about the situations where Gitflow is the better choice. Dogmatically applying trunk-based development everywhere is just as wrong as defaulting to Gitflow everywhere.

Regulated Industries

If you are building software for healthcare (HIPAA), finance (SOC 2, PCI-DSS), or government (FedRAMP), your compliance requirements may mandate formal release processes with documented approval chains. Gitflow's release branches provide a natural audit trail: you can point to a specific release branch, show every commit that went into it, and demonstrate that each one was reviewed and approved. Trunk-based development can satisfy these requirements too (with tagged releases and signed commits), but the mapping to compliance frameworks is less intuitive, and auditors tend to be more comfortable with Gitflow's explicit release ceremony.

Mobile Apps with App Store Reviews

Mobile apps have a fundamentally different deployment model than web applications. When you submit a build to the Apple App Store or Google Play, it goes through a review process that takes one to three days. You cannot deploy a hotfix in minutes. You may have multiple versions in the wild simultaneously (not every user updates immediately). This environment suits Gitflow's release branches because you genuinely need to maintain parallel release tracks: the current production version, the version in review, and the next version in development.

Open Source Projects with Multiple Supported Versions

If you maintain an open source library that supports multiple major versions (like React supporting v17 and v18 simultaneously), Gitflow's long-lived branches map naturally to version maintenance. Security patches and bug fixes need to land on multiple branches independently. Trunk-based development assumes a single deployable artifact, which does not fit this model.

Large Teams Without Strong CI/CD

If your CI pipeline takes 45 minutes and your test suite is unreliable, switching to trunk-based development will make things worse, not better. Trunk-based development assumes fast, reliable CI as a prerequisite. If you cannot get your pipeline under 15 minutes, fix that first. Gitflow's longer-lived branches at least give you isolation while the pipeline is slow, even though they create their own problems.

For the vast majority of startups building SaaS products with web deployments, trunk-based development is the right call. But know your context. If you are in one of the categories above, Gitflow or a hybrid approach may serve you better.

Team Size Considerations and Scaling

The dynamics of branching strategies shift significantly as your team grows. What works for three developers will not work for thirty, and what works for thirty will not work for three hundred.

Solo Developer to 3 People

At this size, the branching strategy almost does not matter. You could commit directly to main with no branches at all, and it would be fine. The value of trunk-based development here is not about merge conflicts (there will be few) but about building the right habits early. If you start with trunk-based development, you build the muscle memory of small commits, fast reviews, and continuous integration. When you grow to eight people, the transition is seamless. If you start with Gitflow, the overhead of release branches and dual merges is pure waste for a team this small.

4 to 10 Developers

This is where the branching strategy starts to matter significantly. With 4 to 10 developers all shipping to the same codebase, merge conflicts become a daily reality under Gitflow. Feature branches that live for a week create compounding integration problems. Trunk-based development shines here because it forces small, frequent integrations that keep the codebase coherent. Code reviews stay fast because PRs are small. Onboarding new developers is easier because they can follow the simple "branch, change, PR, merge" loop without learning the Gitflow branch hierarchy. If you are hiring your fourth or fifth engineer, this is the time to establish trunk-based development as the standard, and having solid developer onboarding practices makes the transition smoother.

11 to 30 Developers

At this scale, you need more tooling support: merge queues, automated checks for branch age (flag any branch older than 24 hours), and clear code ownership rules (CODEOWNERS files in GitHub) so that reviews get routed to the right people quickly. Some teams at this size split into multiple repositories or adopt a monorepo with path-based ownership. Either approach works with trunk-based development, but the monorepo path requires investment in build tooling (Turborepo, Nx, or Bazel) to keep CI times fast.

30+ Developers

At this size, you are likely splitting into multiple teams with separate services. Each service has its own repository (or its own path in a monorepo) and its own trunk. The branching strategy applies within each service, not across the organization. Cross-service coordination happens through API contracts, integration tests, and deployment orchestration, not through branches. If you have reached this scale, you probably also have a platform engineering team that manages CI/CD infrastructure, and they should be the ones defining and enforcing the branching standards.

Migrating from Gitflow to Trunk-Based Development

If you are currently using Gitflow and want to switch, do not try to flip the entire team in one day. A phased migration reduces risk and gives your team time to build the new skills (small PR decomposition, feature flags) that trunk-based development requires.

Phase 1: Shorten Branch Lifetimes (Weeks 1 to 2)

Keep Gitflow's structure but enforce a rule: no feature branch lives longer than three days. This is not trunk-based development yet, but it addresses the worst pain point immediately. Set up a GitHub Action or bot that posts a warning on any PR whose branch is older than 48 hours and escalates to the team lead at 72 hours. You will see merge conflicts drop dramatically in the first week.

Phase 2: Eliminate the Develop Branch (Weeks 3 to 4)

Merge develop into main. Configure your CI/CD pipeline to deploy from main (to staging, not directly to production). Feature branches now branch from and merge into main. You have effectively moved to trunk-based development, but you may still have a release branch for production deployments. That is fine for now.

Phase 3: Add Feature Flags (Weeks 3 to 6)

In parallel with Phase 2, implement a basic feature flag system. Start with the simplest approach: a config file or environment variables. Identify one upcoming feature that would normally be a long-lived branch and build it behind a flag instead. This is the team's learning experience. Expect it to feel awkward the first time. The second time will feel natural.

Phase 4: Drop Release Branches (Weeks 5 to 8)

Once the team is comfortable with feature flags and short-lived branches, eliminate release branches. Switch to either continuous deployment (every merge to main goes to production) or tagged releases (tag a commit on main when you are ready to ship). Implement a merge queue if your team has more than five active contributors.

Phase 5: Optimize the Pipeline (Ongoing)

With the full trunk-based workflow in place, focus on pipeline speed. Parallelize tests. Add caching for dependencies and build artifacts. Set a target: under 10 minutes from push to green. Monitor branch lifetimes and flag anything over 24 hours. Celebrate the team when you hit a streak of zero merge conflicts.

Common Pitfalls During Migration

  • Not investing in CI first. If your pipeline takes 30 minutes, fix that before starting the migration. Trunk-based development with a slow pipeline is worse than Gitflow.
  • Skipping feature flags. Without flags, developers will resist merging incomplete work to main. Feature flags are the bridge that makes the whole model work.
  • Trying to convert the whole team at once. Start with one or two developers who are enthusiastic about the change. Let them prove the model on a real feature. Then expand to the rest of the team with a working example and established patterns.
  • Forgetting to update documentation. Your contributing guide, onboarding docs, and CI configuration all reference the old Gitflow workflow. Update them as you migrate so new hires do not get confused by stale instructions.

The migration typically takes six to eight weeks for a team of 3 to 10 developers. The productivity gains show up almost immediately, usually in the first two weeks, as merge conflicts disappear and PR review times drop. By week eight, most teams wonder why they ever used Gitflow in the first place.

If you are planning a migration and want help structuring it around your team's specific codebase and deployment setup, book a free strategy call and we will map out a migration plan that fits your timeline.

Need help building this?

Our team has launched 50+ products for startups and ambitious brands. Let's talk about your project.

trunk-based developmentGitflow branching strategyCI/CD for startupsfeature flagsGit workflow best practices

Ready to build your product?

Book a free 15-minute strategy call. No pitch, just clarity on your next steps.

Get Started