For years, “Terraform” and “the open-source infrastructure-as-code tool everyone uses” were the same sentence. That stopped being automatically true when HashiCorp relicensed Terraform from the Mozilla Public License (MPL 2.0) to the Business Source License (BSL), a license that restricts building certain kinds of competing commercial products on top of the software while otherwise remaining source-available. The community response was a fork — OpenTofu, adopted by the Linux Foundation — that kept building on the last MPL-licensed codebase. Two years on, both projects are actively maintained, and the practical question for most teams isn’t philosophical, it’s operational: does switching cost more than it saves, and if you do switch, how do you do it without a weekend of state-file panic.

This isn’t a licensing opinion piece. It’s a guide to the actual mechanics: what’s compatible, what to check before you touch anything, the exact migration steps, and how to roll back if something goes sideways.

What Actually Changed

The license change affects redistribution and commercial-competitor terms, not day-to-day usage — running terraform apply against your own infrastructure was never restricted by the BSL change, and most teams reading this were never in the license’s crosshairs to begin with. What it did change: HashiCorp’s own governance controls the codebase’s future direction unilaterally, and organizations building competing managed-Terraform products (the license’s actual target) can’t legally do so off HashiCorp’s code past that license boundary. OpenTofu exists because a group of companies and contributors wanted a permissively-licensed, community-governed continuation of the pre-BSL codebase, and the Linux Foundation now stewards it as a neutral home so no single vendor controls its roadmap.

The two codebases started identical and have diverged since, adding independent features on each side. Providers, however, are a separate ecosystem (published to their own registries) and largely unaffected by which core binary calls them — the compatibility question is really about the CLI/core, not the providers you depend on.

Is Migration Worth It For You

SituationLean toward
Solo/small team, self-hosted state, no HashiCorp commercial products in playEither works; OpenTofu if you value the license and governance model, Terraform if you want HashiCorp’s latest features first
Already using Terraform Cloud/Enterprise for remote runs and RBACStaying on Terraform is simpler — those are HashiCorp’s own hosted products
Building a product that resells Terraform-like automation to third partiesRead the BSL text carefully or talk to counsel; this is the actual audience the license targets
Heavy reliance on a very new Terraform-only featureCheck OpenTofu’s changelog before assuming parity — it usually catches up, but not always same-week
Large existing module library referencing terraform.io docs internallyCosmetic friction only; tofu is a drop-in CLI rename in the vast majority of cases

For a small, self-hosted setup — the kind running Terraform against a handful of cloud accounts with S3 or a similar backend — the honest answer is that the migration is mostly about principle and long-term optionality, not solving an active problem. It’s low-risk enough that “worth it” mostly comes down to whether you want to make the switch, not whether you’re forced to.

State File Compatibility

This is the detail that makes migration low-risk: OpenTofu reads and writes the same state file format Terraform uses. There’s no state conversion step, no schema migration, no special export/import dance. A state file produced by terraform apply opens cleanly with tofu plan and vice versa, because OpenTofu forked at a point where the state format was already stable and hasn’t diverged it.

# This works exactly as you'd expect — no conversion needed
$ file terraform.tfstate
terraform.tfstate: JSON data

$ tofu state list
aws_s3_bucket.terraform_state
aws_dynamodb_table.terraform_locks

The one place to actually check is the required_version and backend blocks in your existing configs — some backend configurations reference terraform explicitly in ways that need a quick look, and any CI pipeline hardcoding the terraform binary name needs updating regardless of state compatibility.

Provider Registry

OpenTofu maintains its own registry (registry.opentofu.org), but it mirrors the Terraform Registry’s providers rather than requiring every provider maintainer to publish twice — in practice, the same hashicorp/aws, hashicorp/google, and community providers you already use are resolvable through it without changes to your provider blocks in most cases.

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

This block doesn’t need to change at all for a migration — OpenTofu resolves hashicorp/aws the same way. Where teams do add an explicit registry override, it’s usually for provider mirrors behind a private registry proxy, which is a separate concern from the OpenTofu migration itself.

Migration Steps

The migration is designed to be additive and reversible: install tofu alongside terraform, point it at your existing state, verify a clean plan, and only then make it the default in CI.

# 1. Install OpenTofu without removing Terraform
brew install opentofu
# or: download the binary from github.com/opentofu/opentofu/releases

$ tofu version
OpenTofu v1.8.0
on linux_amd64

# 2. From an existing working directory with Terraform state already configured,
#    just run init — no special migration command needed
$ tofu init
Initializing the backend...
Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
OpenTofu has been successfully initialized!

# 3. Confirm a clean plan against existing state — this should show NO changes
#    if nothing in your actual infrastructure or config has drifted
$ tofu plan
No changes. Your infrastructure matches the configuration.

# 4. Only after a clean plan, start applying with tofu instead of terraform
$ tofu apply

The critical validation step is #3. If tofu plan shows changes you didn’t expect, stop — that’s a signal of either drift that predates the migration (worth investigating regardless of which tool you use) or an actual behavioral difference between the two binaries for your specific config, and it needs to be understood before applying with the new tool.

# .github/workflows/terraform.yml — swap the setup action and binary name
# Before:
- uses: hashicorp/setup-terraform@v3
  with:
    terraform_version: "1.9.0"
- run: terraform plan

# After:
- uses: opentofu/setup-opentofu@v1
  with:
    tofu_version: "1.8.0"
- run: tofu plan

The .terraform.lock.hcl file — the dependency lock file pinning exact provider versions and checksums — is compatible between both tools and doesn’t need regeneration; tofu init reads it the same way terraform init does.

Rollback

Because state is shared format and nothing about the migration is destructive, rollback is just “stop running tofu and run terraform again”:

# Nothing to undo in the state file itself — just resume using terraform
$ terraform plan
No changes. Your infrastructure matches the configuration.

The only things that need reverting are cosmetic: CI pipeline steps back to hashicorp/setup-terraform, any wrapper scripts referencing the tofu binary name, and documentation. There’s no state export/import to reverse because there was never a conversion in the first place — this is the direct consequence of the two tools sharing a state format.

# If you'd renamed local aliases during the trial period, just point back:
alias terraform='/usr/local/bin/terraform'  # instead of the tofu alias

Mixed-Team Transition Period

For a team migrating gradually rather than flipping a single switch, both binaries can coexist against the same state file without conflict, as long as everyone respects the same lock (whether that’s a DynamoDB lock table, an S3 conditional-write lock, or whatever your backend uses) — the lock mechanism is a backend-level concept, not something tied to which CLI acquired it.

# Alice runs terraform, Bob runs tofu, same S3+DynamoDB backend, same state key
# Both correctly respect the lock — whichever one is running holds it,
# and the other blocks until it's released
$ terraform apply
Acquiring state lock. This may take a few moments...
Error: Error acquiring the state lock
Lock Info:
  ID:        7c2e1e3a-...
  Path:      prod/terraform.tfstate
  Operation: OperationTypeApply
  Who:       bob@workstation

This makes a gradual, low-drama migration possible: move one repo or one environment at a time, confirm clean plans, and let the rest follow once the pattern is proven.

Key Takeaways

  • The BSL relicensing restricts building competing commercial products off HashiCorp’s Terraform code; it does not restrict ordinary usage against your own infrastructure.
  • OpenTofu is the Linux Foundation-stewarded fork from the last MPL-licensed Terraform codebase, with independent governance going forward.
  • State file format is unchanged and shared between both tools — there is no state conversion step in a migration.
  • tofu init against existing Terraform-managed state, followed by a clean tofu plan, is the whole migration; anything showing unexpected diff needs investigation before proceeding.
  • Provider blocks (hashicorp/aws, etc.) and the .terraform.lock.hcl file work unchanged — OpenTofu’s registry mirrors the same providers.
  • Rollback is just reverting to the terraform binary — there’s nothing to undo in the state itself.
  • Mixed teams can run both tools against the same backend during a transition, as long as the backend’s own locking mechanism is respected by both.