Back to blog

Trunk-Based Development: A Guide for Beginners

Understanding trunk-based development: core concepts, best practices, and examples.

March 19, 2025
@berta.codes
9 min read
Trunk-Based Development: A Guide for Beginners

Prerequisites #

Before diving into trunk-based development, you should be familiar with:

• Basic Git commands (commit, push, pull, merge)

• Your team's primary programming language

• Basic concept of branches in version control

• What a pull request/merge request is

Key Terms to Know First Branch

A separate line of development in your codebase. Think of it like creating a copy of your project where you can make changes without affecting the original version. Branches allow multiple developers to work on different features simultaneously without interfering with each other's work. When you're satisfied with your changes, you can merge your branch back into the main codebase.

Trunk/Main Branch

The primary branch (usually called 'main' or 'master') where all code eventually merges. This branch represents the single source of truth for your project and should always contain working, deployable code. In trunk-based development, this is where all feature branches merge into frequently, often multiple times per day. Think of it as the backbone of your project where all completed work comes together.

CI/CD

Continuous Integration/Continuous Deployment - automated processes for integrating and deploying code. CI ensures that whenever code is pushed, it's automatically built and tested to catch problems early. CD takes this a step further by automatically deploying verified code to production environments. Together, they form a pipeline that helps teams deliver code changes more frequently and reliably.

Feature Toggle

A switch in your code that turns features on/off without deploying new code. Feature toggles allow you to deploy incomplete features to production while keeping them hidden from users. They're like light switches in your code - you can turn features on for testing, specific users, or gradually roll them out to more people. This is especially useful in trunk-based development where code is merged frequently but might not be ready for all users.

Pull Request (PR)

A request to merge your code changes into another branch. Pull requests are like asking for a code review - they show others what changes you've made and allow team members to comment, suggest improvements, or approve the changes. They serve as a checkpoint where code quality can be verified before it gets merged into the main branch. Think of it as asking for permission to add your changes to the shared codebase.

Merge Conflict

When Git can't automatically combine changes from different branches. This happens when two developers modify the same lines of code in different ways. Git doesn't know which changes to keep, so it needs human intervention to resolve the conflict. It's like two people editing the same sentence in a document differently - someone needs to decide which version (or combination of versions) to keep.

What is Trunk-Based Development?

Think of trunk-based development like working on a shared document with your team. Instead of everyone having their own copy (branch) for days or weeks, you:

  1. Make small changes frequently
    1. Update the main document (trunk) at least once a day
      1. Keep your personal copy (feature branch) for no more than 1-2 days

      Traditional Branching:
      main     ----o--------o--------o-------- (rare merges)
      feature1      \----------------/
      feature2          \------------------/
      feature3              \---------------/
      
      Trunk-Based Development:
      main     ----o--o--o--o--o--o--o------ (frequent merges)
      feature1      \-/
      feature2          \-/
      

      feature3 \-/

      Core Concepts for Beginners:

      In trunk-based development:

      • All developers work on a single main branch (the "trunk")

      • Changes are integrated frequently (ideally daily, but the exact frequency depends on team practices)

      • Feature branches, when used, are short-lived (typically 1-2 days maximum)

      • The trunk should always be in a releasable state

      • Feature toggles are used to manage incomplete features in production

      How to Recognize Trunk-Based Development

      A project using trunk-based development typically shows these characteristics:

      1. Repository Structure

      • Single main branch with high commit frequency

      • Few, short-lived feature branches

      • No long-running release branches

      • Automated CI/CD pipeline with frequent deployments

      1. Development Patterns

      • Multiple commits to main branch daily

      • Feature toggles in the codebase

      • Comprehensive automated testing

      • Emphasis on small, incremental changes

      Common Pitfalls for Beginners 1. Making Too Big Changes

      Wrong:

      Working on a huge feature for days without merging

      Right:

      Break down features into small, mergeable chunks

      2. Not Testing Enough

      Wrong:

      Pushing directly to trunk without running tests

      Right:

      Always run local tests before pushing

      3. Poor Communication

      Wrong:

      Not telling team members about your changes

      Right:

      Regularly update team on what you're working on

      4. Fear of Merging Often

      Wrong:

      Holding onto your branch because you're nervous about merging

      Right:

      Merge small changes frequently, use feature toggles for incomplete work

      Your First Day with Trunk-Based Development
      Note: These commands are basic examples. Always follow your team's specific Git workflow and branch naming conventions. Some teams might use additional steps or different commands based on their setup.

      Here's what a typical day looks like:

      1. Morning:

      git checkout main
         git pull                # Get latest changes
      

      git checkout -b my-feature # Create new branch

      2. <strong>During the day</strong>:

      bash

      git add .

      git commit -m "Add login form validation"

      git pull origin main # Stay up to date

      3. <strong>End of day</strong>:

      bash

      git push

      # Create Pull Request

      # Get review

      # Merge to main

      When to Use Trunk-Based Development Ideal Scenarios
      1. Continuous Delivery Requirements

      • Need for frequent releases

      • Emphasis on fast feedback cycles

      • Focus on continuous integration

      1. Team Characteristics

      • Strong automated testing practices

      • Good code review culture

      • Experienced in feature toggles

      • Strong communication channels

      1. Project Types

      • Web applications with frequent updates

      • Services requiring rapid iteration

      • Products with continuous delivery needs

      When to Consider Alternatives
      1. Team Scenarios

      • Large teams without proper CI/CD infrastructure

      • Teams new to automated testing

      • Projects requiring extensive code review processes

      1. Project Types

      • Systems requiring formal release processes

      • Highly regulated environments

      • Projects with long validation cycles

      Implementation in React Applications #

      Note: The following examples demonstrate one way to implement trunk-based development in a React project. Keep in mind that different teams and organizations might have their own preferred approaches, tools, and patterns. The key is to understand the core principles and adapt them to your team's specific needs and requirements.

      Let's start with a simple example that juniors can easily follow:

      1. Basic Feature Toggle
      Important: This is a simplified example for learning purposes. For production use, consider using established feature flag services or libraries that handle persistence, user targeting, and analytics.

      // A simple feature toggle without complexity
      const FEATURES = {
        newHeader: false,
        betaFeatures: false
      };
      
      function MyComponent() {
        if (FEATURES.newHeader) {
          return <NewHeader />;
        }
        return <OldHeader />;
      

      }

      2. Feature Implementation

      // src/components/NewFeature.tsx
      import { useFeature } from '../features/FeatureManager';
      
      export const EnhancedUserProfile: React.FC = () => {
        const isEnabled = useFeature('enhanced-profile');
      
        if (!isEnabled) {
          return <UserProfile />;
        }
      
        return (
          <div>
            <UserProfile />
            <AdvancedSettings />
            <ActivityFeed />
          </div>
        );
      

      };

      Challenges and Solutions 1. Code Conflicts Challenge: More frequent merges can lead to increased conflicts. Solutions:

      • Small, frequent commits

      • Clear team communication

      • Well-defined component boundaries

      • Automated conflict detection

      2. Incomplete Features Challenge: Managing partially completed features in production code. Solution: Implement robust feature management:

      // src/config/features.ts
      interface FeatureConfig {
        name: string;
        rolloutPercentage: number;
        enabledEnvironments: string[];
        dependencies: string[];
      }
      
      const featureConfigs: FeatureConfig[] = [
        {
          name: 'enhanced-profile',
          rolloutPercentage: 20,
          enabledEnvironments: ['staging', 'production'],
          dependencies: ['user-settings', 'activity-feed'],
        },
      ];
      
      export const getEnabledFeatures = (environment: string): string[] => {
        return featureConfigs
          .filter(f => f.enabledEnvironments.includes(environment))
          .map(f => f.name);
      

      };

      3. Testing Strategy Challenge: Maintaining code quality with frequent integrations. Solutions:

      // src/components/UserDashboard.test.tsx
      import { render, screen, waitFor } from '@testing-library/react';
      import { UserDashboard } from './UserDashboard';
      
      describe('UserDashboard', () => {
        it('loads with feature flags', async () => {
          render(
            <FeatureProvider features={{ 'enhanced-profile': true }}>
              <UserDashboard />
            </FeatureProvider>
          );
      
          await waitFor(() => {
            expect(screen.getByTestId('enhanced-profile')).toBeInTheDocument();
          });
        });
      
        it('handles disabled features gracefully', async () => {
          render(
            <FeatureProvider features={{ 'enhanced-profile': false }}>
              <UserDashboard />
            </FeatureProvider>
          );
      
          expect(screen.queryByTestId('enhanced-profile')).not.toBeInTheDocument();
        });
      

      });

      Best Practices for Success #

      1. Code Integration

      • Merge to trunk at least once per day

      • Keep feature branches short (1-2 days maximum)

      • Use feature toggles for incomplete work

      • Implement comprehensive automated testing

      1. Team Practices

      • Regular communication about feature development

      • Quick code review turnaround

      • Pair programming for complex features

      • Clear documentation of feature toggles

      1. Technical Requirements

      • Automated CI/CD pipeline

      • Comprehensive test coverage

      • Feature toggle management system

      • Monitoring and observability tools

      1. Deployment Strategy

      • Automated deployment pipeline

      • Rollback capabilities

      • Feature toggle controls

      • Gradual rollout mechanisms

      Measuring Success

      Key metrics to track:

      1. Development Metrics

      • Deployment frequency

      • Lead time for changes

      • Change failure rate

      • Mean time to recovery

      1. Team Metrics

      • Code review turnaround time

      • Number of active branches

      • Feature toggle usage

      • Test coverage trends

      Conclusion #

      Trunk-based development is a powerful approach that can significantly improve development efficiency and software delivery when implemented correctly. However, it requires the right team culture, technical practices, and tooling to be successful. Consider your team's experience, project requirements, and existing infrastructure when deciding if trunk-based development is the right choice for your organization.

      Further Reading

      Trunk Based Development

      Atlassian's Guide to Trunk-Based Development

      Feature Toggles Best Practices

      CI/CD Best Practices

      Troubleshooting Guide #

      Common issues you might face and how to solve them:

      1. Merge Conflicts

      # If you get a merge conflict:
      git status                 # See which files are conflicted
      git pull origin main      # Get latest changes
      # Fix conflicts in your editor
      git add .
      

      git commit -m "Resolve conflicts"

      2. Feature Toggle Issues

      // Always provide a fallback
      function MyFeature() {
        if (!isFeatureEnabled('newFeature')) {
          return <OldFeature />; // Fallback
        }
        return <NewFeature />;
      

      }

      Resources for Beginners #

      Git Basics

      Interactive Git Learning

      Feature Toggle Patterns

      CI/CD for Beginners

Share this post