Terraform to OpenTofu Migration in 2026 — The Post-BSL Decision Framework for Azure Teams

By Law Wen Feng | June 2026


Two years ago, I wrote about HashiCorp's switch from the Mozilla Public License (MPL) to the Business Source License (BSL) and the community's response — the creation of OpenTofu under the Linux Foundation. At the time, many of us in the Azure ecosystem took a wait-and-see approach. OpenTofu was promising, but it hadn't yet reached feature parity. In 2026, that has changed. If you're leading an Azure-first team in Southeast Asia and still running Terraform, it's time to make a deliberate decision — not just react to blog posts.

This article lays out the decision framework I use with clients: a practical, no-hype assessment of what OpenTofu offers today, when Terraform (and IBM's stewardship) still makes sense, and when Azure-native tooling like Bicep deserves a second look.

The State of Play in 2026

What Happened with BSL

In August 2023, HashiCorp relicensed Terraform and its entire toolchain from MPL 2.0 to the Business Source License v1.1. The BSL is not open source by the Open Source Definition — it permits use but restricts competitive commercial use. If you're building a product that competes with HashiCorp Cloud Platform (HCP), you can't use the BSL-licensed code.

In 2025, IBM completed its acquisition of HashiCorp. The acquisition didn't change the BSL terms, but it raised legitimate questions about long-term stewardship. For most end-users running terraform apply in their CI/CD pipelines, the BSL doesn't directly restrict usage. But for teams building internal platforms, CI tooling, or drift-detection systems that wrap Terraform, the license creates real legal and architectural constraints.

My take: if you're an enterprise team simply applying infrastructure, the BSL itself may not be your primary concern. But the governance model matters. IBM's priorities shift. The Linux Foundation's governance of OpenTofu doesn't.

OpenTofu's Feature Parity Milestone

As of OpenTofu 1.10 (released early 2026), the project has reached genuine feature parity with Terraform for the vast majority of Azure workloads. Here's what matters:

State Encryption. Since OpenTofu 1.7, state files can be natively encrypted at rest using AES-256-GCM. This was a community priority from day one. In 1.10, external key provider support is fully mature — you can integrate with Azure Key Vault, HashiCorp Vault, or any secrets manager through a simple command-line provider. This is something Terraform still doesn't offer natively.

Removed Blocks. The removed block lets you clean up state without destroying infrastructure. This is incredibly useful for decommissioning resources that were managed by OpenTofu but are being retired or moved to another system.

removed {
  from = azurerm_network_security_rule.legacy
  lifecycle {
    destroy = false
  }
}

Dynamic Provider Configurations. OpenTofu 1.8 introduced early evaluation of variables, letting you use var and local references in backend blocks and module sources. Before this, you couldn't parameterize your state backend. Now you can.

terraform {
  backend "azurerm" {
    resource_group_name  = var.state_resource_group
    storage_account_name = var.state_storage_account
    container_name       = var.state_container
    key                  = "${var.environment}/main.tfstate"
  }
}

OCI Registry Support. OpenTofu 1.10 can pull providers and modules from OCI-compliant container registries. For air-gapped Azure environments (common in government and banking sectors across Malaysia and Singapore), this eliminates the dependency on public registries.

Native S3 State Locking. No more DynamoDB dependency for S3 backends. OpenTofu uses S3's conditional writes natively. For Azure teams, this matters less (we use Azure Blob), but it signals the project's engineering maturity.

The bottom line: OpenTofu is no longer a "promising fork." It's a production-ready tool with features Terraform doesn't have.

The 3-Command Migration

I know this sounds too simple. It's not. The real work is in the preparation. But the actual tool migration from Terraform to OpenTofu is genuinely three commands:

# 1. Back up your state (do this regardless)
az storage blob download \
  --account-name mystataccount \
  --container-name tfstate \
  --name main.tfstate \
  --file ./backups/main.tfstate.bak

# 2. Install OpenTofu and initialize
tofu init upgrade

# 3. Validate with a plan — should be identical to your last terraform plan
tofu plan -out=tfplan

That's it. OpenTofu reads the same HCL configuration files, the same state format, and the same provider binaries. If tofu plan shows a clean plan identical to what terraform plan showed, you've migrated.

The preparation work is where the real effort lives:

  1. Audit your provider versions. OpenTofu supports the same Terraform Registry providers. Pin your versions explicitly and confirm they're available.
  2. Review any Terraform-specific features you use. If you're using Terraform Cloud state locking, HCP Terraform workspaces, or Sentinel policies, those require separate planning.
  3. Update your CI/CD pipelines. Swap terraform commands for tofu (or alias it — OpenTofu respects TF_CLI_ARGS env vars).
  4. Test with a non-critical environment first. I recommend starting with a dev or staging subscription.

Decision Matrix: OpenTofu vs Terraform Cloud vs Bicep

This is the question I get asked most often. There's no universal answer, but here's how I frame it:

Choose OpenTofu if:

  • You want permissive, OSI-approved licensing (MPL 2.0) with no commercial restrictions.
  • Your team builds internal platforms or wraps IaC in custom tooling — BSL would be a legal concern.
  • State encryption is a compliance requirement (it's native in OpenTofu, not in Terraform).
  • You prefer Linux Foundation governance over IBM stewardship.
  • You need fast release cadence — OpenTofu ships monthly, Terraform quarterly.
  • You're in an air-gapped or highly regulated Azure environment where OCI registry support matters.

Choose Terraform Cloud (HCP Terraform) if:

  • Your team already pays for HCP Terraform and deeply uses its managed state, policy-as-code (Sentinel), and run trigger features.
  • You need vendor-backed SLAs for compliance audits in regulated industries.
  • Your workloads rely on Terraform-specific features like Stacks or native Sentinel integration.
  • Migration cost outweighs licensing concern — if BSL doesn't affect your use case, stay.

Choose Bicep if:

  • You are 100% Azure-native with no multi-cloud requirements.
  • You want first-class ARM template integration and Azure CLI tooling.
  • Your team already has strong Bicep/Azure CLI skills and no HCL investment.
  • You prefer Microsoft's governance over community or third-party governance.
  • You're building greenfield projects without existing Terraform state.

For most of my clients — Azure-first teams in Southeast Asia with existing Terraform investments — the answer is OpenTofu. Bicep is excellent for greenfield Azure-only work, but switching IaC languages mid-flight is a much bigger lift than swapping the CLI binary.

GitHub Actions CI/CD with OpenTofu

If you're running Azure deployments through GitHub Actions, here's a practical CI/CD pattern using OpenTofu. This is a simplified version of what I deploy for clients:

name: OpenTofu Azure Deploy

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
  ARM_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
  ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
  ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
  TF_VERSION: "1.10.3"

jobs:
  plan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup OpenTofu
        uses: opentofu/setup-opentofu@v1
        with:
          tofu_version: ${{ env.TF_VERSION }}
          tofu_wrapper: false

      - name: OpenTofu Init
        run: tofu init -backend-config="backend.tfvars"

      - name: OpenTofu Format Check
        run: tofu fmt -check -recursive

      - name: OpenTofu Validate
        run: tofu validate

      - name: OpenTofu Plan
        id: plan
        run: tofu plan -no-color -out=tfplan
        continue-on-error: true

      - name: Upload Plan Artifact
        uses: actions/upload-artifact@v4
        with:
          name: tfplan
          path: tfplan

  apply:
    needs: plan
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4

      - name: Setup OpenTofu
        uses: opentofu/setup-opentofu@v1
        with:
          tofu_version: ${{ env.TF_VERSION }}
          tofu_wrapper: false

      - name: Download Plan
        uses: actions/download-artifact@v4
        with:
          name: tfplan

      - name: OpenTofu Apply
        run: tofu apply -auto-approve tfplan

A few things to note about this pipeline:

  • The opentofu/setup-opentofu action is maintained by the OpenTofu project. It's the equivalent of hashicorp/setup-terraform.
  • We store the plan artifact between jobs — this ensures the apply uses the exact same plan that was reviewed.
  • For state encryption with Azure Key Vault, add this to your backend configuration:
terraform {
  encryption {
    key_provider "external" "azkv" {
      command = ["az", "keyvault", "secret", "show",
                "--vault-name", "mykeyvault",
                "--name", "opentofu-state-key",
                "--query", "value", "-o", "tsv"]
    }

    method "aes_gcm" "state" {
      keys = key_provider.external.azkv
    }

    state {
      method = method.aes_gcm.state
    }
  }
}

This encrypts your state file end-to-end using a key stored in Azure Key Vault. If your compliance team has asked "is our state encrypted at rest?" — this is the answer.

Azure-Specific Considerations

Working in the Azure ecosystem with OpenTofu brings a few Azure-specific nuances worth calling out:

Provider Compatibility. The azurerm provider is fully compatible with OpenTofu. It's MPL-licensed and available in the OpenTofu registry. No changes needed to your provider blocks.

State Backend. Azure Blob Storage works as a backend for both tools. If you're using the azurerm backend, your configuration carries over unchanged:

terraform {
  backend "azurerm" {
    resource_group_name  = "rg-terraform-state"
    storage_account_name = "stterraformstate"
    container_name       = "tfstate"
    key                  = "prod/aks.tfstate"
  }
}

Azure Identity. OpenTofu supports the same Azure authentication mechanisms — ARM_CLIENT_ID/ARM_CLIENT_SECRET for service principals, or Workload Identity for GitHub Actions and AKS workloads. No changes needed.

Bicep as a Co-Existence Strategy. I've seen teams successfully use Bicep for subscription-level governance (management groups, policy assignments, RBAC) while using OpenTofu for resource-level infrastructure (AKS clusters, databases, networking). This hybrid approach gives you the best of both worlds — Microsoft-native governance with OpenTofu's flexibility and licensing.

Private Endpoints and Air-Gapped Environments. OpenTofu 1.10's OCI registry support is particularly valuable here. You can mirror providers to Azure Container Registry and configure tofu init to pull from your private registry:

provider_installation {
  oci_mirror {
    repository_template = "myacr.azurecr.io/opentofu-providers/${namespace}/${type}"
    include             = ["registry.opentofu.org/azurerm/*"]
  }
}

What I Tell My Clients

After walking through the technical details, here's the practical advice I give Azure-first teams in the region:

  1. If you're running Terraform today and it works, you don't need to panic. The BSL doesn't force you to do anything tomorrow. But you should plan a migration window.
  2. The migration is a weekend project, not a quarter-long initiative. Three commands to swap the binary. A week of testing. Then you're done.
  3. State encryption alone justifies the move for many organizations. If your security team has ever asked about state file protection, OpenTofu gives you a native, auditable answer.
  4. Don't use this as an excuse to rewrite everything in Bicep. Unless you have zero existing Terraform investment and are 100% Azure-only, the migration cost isn't worth it. OpenTofu is a drop-in replacement, not a rewrite.
  5. Governance matters more than features. OpenTofu's Linux Foundation governance gives you a community-driven roadmap that isn't beholden to any single vendor's quarterly earnings. In a region where vendor lock-in is a real concern, this matters.

Key Takeaways

  1. OpenTofu 1.10 has reached genuine feature parity with Terraform for Azure workloads, including state encryption, removed blocks, dynamic provider configurations, and OCI registry support — features Terraform doesn't offer natively.
  2. The migration is a drop-in replacement. Swap the terraform binary for tofu, run tofu init upgrade, and validate with tofu plan. Your HCL code, state files, and providers carry over unchanged.
  3. The BSL license doesn't force you to migrate, but it should inform your decision. If your team builds internal platforms, wraps IaC in custom tooling, or operates in regulated environments, the licensing and governance model matters.
  4. For Azure-first teams, OpenTofu with Azure Blob backends and Azure Key Vault encryption is the pragmatic choice. It gives you native state encryption, air-gapped registry support, and Linux Foundation governance — all without changing your existing architecture.
  5. Consider a hybrid strategy: Bicep for Azure subscription governance, OpenTofu for resource-level infrastructure. This gives you Microsoft-native policy integration where it matters and OpenTofu's flexibility everywhere else.

Law Wen Feng is a Principal Solution Architect based in Malaysia, specializing in cloud-native architecture and infrastructure automation for enterprise teams across Southeast Asia. Find more at wenfeng.my.