GitFlow combined with Terraform: maybe not the best choice.

Terrateam avatar

Terrateam

GitFlow combined with Terraform: maybe not the best choice. blog post

GitFlow is a popular branching strategy that has served a lot of software teams well, especially using monorepos. The idea is to maintain long-lived branches like develop and main while isolating features, releases, and hotfixes in their own branches. This can help teams work on a repository without stepping on toes.

Here’s how it works:

Branches

  • main → Stable production branch
  • develop → Integration branch for new features
  • feature/ → New feature branches from develop
  • release/ → Prepares a version for production
  • hotfix/ → Urgent fixes for main
  • bugfix/ → Fixes applied before release

Workflow steps

  1. Start development → Branch from develop (feature/)
  2. Merge feature → Back into develop when done
  3. Create a release → Branch from develop (release/)
  4. Finalize release → Merge into main and tag a version
  5. Critical fixes? → Use hotfix/ from main, then merge back

When it comes to infrastructure as code with Terraform or OpenTofu, GitFlow can create a lot of problems.

GitFlow doesn’t work well for Infrastructure as Code

For application development, GitFlow can make sense. Code is stateless, meaning multiple developers can work in parallel without worrying about underlying conflicts beyond merge conflicts. Once merged, branches can be deleted, and nothing breaks.

Infrastructure as code is different. Terraform does not just describe a set of files. It describes real, running infrastructure, and when multiple branches manipulate that infrastructure in parallel, things start to break.

GitFlow breaks down

State file conflicts

Terraform relies on state files to track live infrastructure. If two GitFlow branches modify the same resources, their state files will diverge. Merging those branches is not like merging text files. It is merging two different views of reality.

At best, Terraform detects conflicts and blocks you. At worst, a bad merge causes Terraform to delete or recreate resources unexpectedly. This can lead to downtime or other unintended consequences.

Long-lived branches drift

In GitFlow, feature branches can live for weeks before merging. In the world of Terraform, that is a long time. Infrastructure changes frequently. Resources can get added, deleted, or modified outside of Git, whether manually in the cloud console or by another branch merge.

By the time a long-lived branch finally merges, its plan may look drastically different than expected, resulting in failed applies or infrastructure drift.

Environment promotion don’t mix with git merges

GitFlow assumes that changes move from develop to release to main in a linear way. But infrastructure deployments are rarely that straightforward.

Sometimes you need to apply a change in staging first and verify it before rolling it out to production. Other times, hotfixes need to bypass staging entirely and go straight to production. Multi-region deployments often need to happen in parallel, not one after another.

GitFlow forces infrastructure into a process that does not match how teams actually deploy and promote environments.

Merging Terraform code is not straightforward

Merging application code is usually straightforward. Git reconciles differences in code, and tests confirm everything works.

With infrastructure, a successful merge does not always mean the final result is correct. Terraform will apply the most recent version of a resource, potentially overriding previous changes without warning.

GitFlow is complicated with CI/CD pipelines

GitFlow requires multiple steps for every change. Terraform plan runs on feature branches. Another apply happens when merging into develop. A separate plan runs on a release branch. Another apply happens when merging to main.

Multiply this by multiple environments like staging, production, and multiple regions, and the pipeline becomes a mess of conditional logic and custom workflows. That is a lot of overhead for something that does not match how infrastructure is actually deployed.

Separate environments by directories

GitFlow is not inherently bad, but it does not fit Terraform’s workflow. Instead, consider a simpler approach.

My preferred strategy is to separate environments by directories instead of branches. Instead of maintaining a staging branch, keep a dedicated directory for each environment. This makes it easier to update infrastructure without worrying about complex merge conflicts.

Terminal window
terraform/
├── staging/
├── main.tf
├── variables.tf
├── production/
├── main.tf
├── variables.tf

Conclusion

GitFlow works for application code, but Terraform is different. When you try to force GitFlow onto live infrastructure, you introduce state conflicts, merge risks, and a lot of complexity. Instead of relying on long-lived branches and complex merges, use short-lived feature branches, keep environment configurations separate, and automate your workflows. The best Terraform processes are the ones that keep things simple and predictable.

While GitFlow can introduce complexity for Terraform, some teams still find ways to make it work. At Terrateam, we support GitFlow and other branching strategies, so teams can choose what works best for them.

GitOps-First Infrastructure as Code

Ready to get started?

Build, manage, and deploy infrastructure with GitHub pull requests.