OpenTofu Migration Guide: Moving 200+ Terraform Modules Without Downtime
HashiCorp's BSL licensing change forced a reckoning across the infrastructure-as-code community. OpenTofu — the Linux Foundation-backed fork — emerged as the open-source alternative. But how do you actually migrate a production Terraform estate without breaking everything?
# OpenTofu Migration Guide: Moving 200+ Terraform Modules Without Downtime
HashiCorp's BSL licensing change forced a reckoning across the infrastructure-as-code community. OpenTofu — the Linux Foundation-backed fork — emerged as the open-source alternative. But how do you actually migrate a production Terraform estate without breaking everything?
We've done this migration for three clients now, totaling 200+ modules across multiple AWS accounts. Here's the complete playbook.
Why Migrate Now?
The technical argument is simple: OpenTofu maintains full compatibility with Terraform's HCL syntax and state format. The strategic argument is stronger: your infrastructure tooling shouldn't be subject to unilateral licensing changes by a single vendor.
OpenTofu 1.8+ introduced client-side state encryption — a feature Terraform doesn't offer. The fork is diverging in useful ways.
Pre-Migration Audit
Step 1: Provider Inventory
Not all providers require changes. Run this audit:
# List all providers in use
grep -r "required_providers" --include="*.tf" -l | \
xargs grep "source" | sort -uMost providers (AWS, GCP, Azure, Cloudflare) work identically. Watch for:
hashicorp/consul and hashicorp/vault — these still work but check version compatibilityStep 2: Binary Reference Scan
# Find every reference to 'terraform' binary
grep -rn "terraform " scripts/ .github/ .gitlab-ci.yml Makefile \
--include="*.sh" --include="*.yml" --include="*.yaml" --include="Makefile"We typically find 30-50 references across CI/CD configs, wrapper scripts, Makefiles, and documentation.
Step 3: State File Compatibility Test
OpenTofu reads Terraform state files natively. Verify:
tofu init
tofu state list # Should match terraform state list exactly
tofu state show aws_instance.web # Spot-check a few resourcesMigration Execution
Phase 1: Install OpenTofu
# Linux (snap)
snap install --classic opentofu
# macOS (brew)
brew install opentofu
# Docker
docker pull ghcr.io/opentofu/opentofu:latestPhase 2: CI/CD Pipeline Updates
GitHub Actions:
- uses: opentofu/setup-opentofu@v1
with:
tofu_version: "1.8.0"
- run: tofu init
- run: tofu plan -out=plan.tfplanGitLab CI:
image: ghcr.io/opentofu/opentofu:1.8
script:
- tofu init -backend-config="..."
- tofu planAtlantis: Update repos.yaml to use tofu binary. Atlantis supports OpenTofu natively since v0.28.
Phase 3: Lock File Migration
# Remove old lock file
rm .terraform.lock.hcl
# Regenerate with OpenTofu
tofu init -upgradeThe new lock file (.terraform.lock.hcl — same name) will reference the same provider versions.
Phase 4: Staged Rollout
1. Week 1: Migrate non-critical modules (dev/staging) 2. Week 2: Run tofu plan against production — compare output with last terraform plan 3. Week 3: Switch production pipelines 4. Week 4: Remove Terraform binary, update documentation
Post-Migration: Leveraging OpenTofu-Only Features
Client-Side State Encryption
terraform {
encryption {
method "aes_gcm" "default" {
keys = key_provider.aws_kms.default
}
state {
method = method.aes_gcm.default
}
}
}This encrypts state at rest — before it reaches your backend. Terraform doesn't offer this.
Common Pitfalls
1. Wrapper scripts with version checks — Scripts that run terraform version and parse output will break. Grep for version-parsing logic in your automation. 2. Terragrunt compatibility — Terragrunt supports OpenTofu since v0.54. If you're on an older version, update Terragrunt first, then migrate the binary. 3. IDE plugins — VS Code's Terraform extension works with OpenTofu out of the box. JetBrains users need the separate OpenTofu plugin from the marketplace. 4. Documentation drift — Search-replace "terraform" with "tofu" in all runbooks, READMEs, and onboarding docs. This is easy to forget and causes confusion for new team members. 5. Terraform Cloud/Enterprise dependencies — If you're using Terraform Cloud for remote state or runs, you'll need an alternative. OpenTofu works with any S3/GCS/Azure Blob backend, plus Spacelift and env0 support OpenTofu natively.
Testing Strategy
Don't just run tofu plan and call it done. Build a proper validation matrix:
#!/bin/bash
# migration-test.sh — run against each module
set -euo pipefail
MODULE_DIR=$1
cd "$MODULE_DIR"
# 1. Init
tofu init -upgrade 2>&1 | tee /tmp/tofu-init.log
# 2. Validate
tofu validate
# 3. Plan (compare with last terraform plan)
tofu plan -out=tofu.plan -no-color > /tmp/tofu-plan.txt
# 4. State operations
tofu state list > /tmp/tofu-state.txt
# 5. Compare resource counts
TF_COUNT=$(wc -l < /tmp/tf-state.txt 2>/dev/null || echo 0)
TOFU_COUNT=$(wc -l < /tmp/tofu-state.txt)
if [ "$TF_COUNT" != "$TOFU_COUNT" ]; then
echo "WARNING: Resource count mismatch! TF=$TF_COUNT TOFU=$TOFU_COUNT"
exit 1
fi
echo "Module $MODULE_DIR: PASS"Run this against every module in staging before touching production. We scripted this and ran it across all 200+ modules in under an hour.
Results
For our largest migration (200+ modules, 3 AWS accounts):
The migration is far less scary than it looks. The state compatibility is rock-solid. The only real work is updating your CI/CD pipelines and wrapper scripts — the infrastructure itself doesn't change at all.
Should You Wait?
No. Here's why:
The best time to migrate was when BSL was announced. The second best time is this weekend.
---
Need help migrating your Terraform estate to OpenTofu? We've done this at scale. Book a free consultationBook a free consultationhttps://techsaas.cloud/contact or explore our DevOps servicesDevOps serviceshttps://techsaas.cloud/services.
Need help with general?
TechSaaS provides expert consulting and managed services for cloud infrastructure, DevOps, and AI/ML operations.