Approach Comparison: Terraform vs. OpenTofu in Automated Pipelines
On August 10, 2023, HashiCorp shifted Terraform from the open-source MPL 2.0 license to the Business Source License (BSL 1.1). That single licensing shift triggered immediate questions for platform teams. Did building internal developer platforms violate BSL terms?
Could managed service providers continue offering Terraform-based automation to clients? In response, companies including Gruntwork, Spacelift, and Env0 launched OpenTofu. Now hosted by the Linux Foundation, OpenTofu provides an independently governed fork with permanent open-source licensing.
DevOps teams evaluating continuous delivery today face a clear choice:
- Staying with Terraform: You preserve your current tooling and HashiCorp Cloud integration. However, your legal and platform teams must audit all commercial automation, competitive offerings, and internal tooling for BSL compliance.
- Switching to OpenTofu: OpenTofu forked from Terraform 1.5.6 and remains fully compatible with Terraform 1.5.7 configurations. Existing HCL files, remote state backends, and community providers run without modification under the MPL 2.0 license.
Both binaries share identical execution loops. They pull provider plugins, compute resource diffs against state, and apply approved changes. Migrating a CI/CD pipeline requires three steps: swap the CLI binary, point to the OpenTofu registry, and verify state backend locking.
Pros & Cons of Migrating to OpenTofu
Before updating runners across 50 repositories, weigh the operational payoffs against the friction of switching.
The Advantages
- Independent Foundation Governance: OpenTofu operates under the Linux Foundation. Roadmaps, RFCs, and release cadences are vendor-neutral. No single company can alter the license on a future release.
- Drop-in CLI Parity: Commands map 1:1. Run
tofu init,tofu plan, andtofu applyusing the exact arguments and flags your team already runs with Terraform. - Seamless State Compatibility: If your infrastructure runs on Terraform 1.5.7 or earlier, OpenTofu reads your existing State Format v4 directly. You avoid complex JSON schema conversions or state resets.
- Client-Side State Encryption: Starting in version 1.7.0, OpenTofu introduced native state encryption. You can encrypt sensitive variables and secrets directly on your runner using AWS KMS, GCP KMS, or AES-GCM before writing to remote object storage.
The Potential Drawbacks
- Feature Divergence: Compatibility remains strong for core HCL. However, proprietary features introduced in Terraform 1.7 and later (such as test mocks and specific provider functions) do not carry over automatically.
- CI Ecosystem Packaging: HashiCorp maintains pre-baked setup steps in some cloud marketplaces. Switching to OpenTofu requires updating your pipeline YAML to use the official
opentofu/setup-opentofuaction or container image.
For most platform teams, the migration takes less than two hours per repository. The payoff is immediate: total independence from upstream commercial licensing restrictions.
Recommended Setup for an OpenTofu CI/CD Pipeline
Running IaC in CI/CD demands strict isolation. A secure architecture relies on four baseline guardrails:
- Keyless OIDC Authentication: Eliminate static cloud credentials from repository secrets. Use OpenID Connect (OIDC) to federate authentication between your CI runner and your cloud provider. AWS IAM, Google Cloud Workload Identity, and Azure Entra ID all issue short-lived (typically 1-hour) tokens directly to verified pipeline jobs.
- State Storage with Distributed Locking: Store your state in dedicated remote storage, such as Amazon S3 backed by DynamoDB or Google Cloud Storage with object locking enabled. Fast locking prevents race conditions and corrupt states when parallel pull requests trigger overlapping plans.
- Separated Plan and Apply Stages: Run
tofu planautomatically on pull requests. Export the plan summary directly into PR comments so reviewers can inspect diffs before merging. Restricttofu applystrictly to merged commits on themainbranch. - Strict Version Pinning: Explicitly pin both the OpenTofu binary (e.g.,
1.8.2) and provider versions (e.g., AWS provider~> 5.40). Pinning prevents automated builds from breaking when upstream registries publish major version updates.
Implementation Guide: Migrating from Terraform to OpenTofu in GitHub Actions
Follow these steps to convert an existing Terraform repository to a hardened OpenTofu GitHub Actions workflow.
Step 1: Test Your Local Project with the OpenTofu CLI
Verify that your code compiles locally before committing pipeline changes. Install OpenTofu and test initialization:
# Install OpenTofu on Ubuntu/Debian using the official installer script
curl --proto '=https' --tlsv1.2 -fsSL https://get.opentofu.org/install-opentofu.sh -o install-opentofu.sh
chmod +x install-opentofu.sh
./install-opentofu.sh --install-method deb
rm -f install-opentofu.sh
# Validate your project directory
cd my-infrastructure-repo/
tofu init
tofu plan
If the plan completes without schema warnings or provider failures, your codebase is ready for automated execution.
Step 2: Update Your Versions Configuration
Open versions.tf. Set the required version constraint to support OpenTofu releases and maintain an encrypted S3 backend:
terraform {
# Accepts OpenTofu 1.6+ or Terraform 1.5.7
required_version = ">= 1.5.7"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.40"
}
}
backend "s3" {
bucket = "corp-infrastructure-tfstate-prod"
key = "networking/vpc-production.tfstate"
region = "us-east-1"
dynamodb_table = "corp-tfstate-locks"
encrypt = true
}
}
Step 3: Build the GitHub Actions Pipeline
Create .github/workflows/opentofu.yml. This workflow authenticates via AWS OIDC, checks formatting, posts plan output to pull requests, and applies changes on merge.
name: "OpenTofu Infrastructure Pipeline"
on:
push:
branches:
- main
pull_request:
branches:
- main
permissions:
id-token: write
contents: read
pull-requests: write
jobs:
tofu:
name: "OpenTofu Plan & Apply"
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Configure AWS Credentials via OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions-opentofu
aws-region: us-east-1
- name: Setup OpenTofu
uses: opentofu/setup-opentofu@v1
with:
tofu_version: 1.8.2
- name: Initialize OpenTofu
run: tofu init
- name: Validate Formatting
run: tofu fmt -check
- name: Run Speculative Plan
id: plan
if: github.event_name == 'pull_request'
run: |
tofu plan -no-color -out=plan.tfplan
continue-on-error: false
- name: Publish Plan Summary to Pull Request
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const body = `#### OpenTofu Plan Result: \`Success\`
* **Pushed by:** @${context.actor}
* **Action:** \`${context.eventName}\`
* **Target Branch:** \`${context.payload.pull_request.base.ref}\``;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
});
- name: Apply Approved State
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: tofu apply -auto-approve
Step 4: Execute Cutover and Validate State Integrity
Deploy the updated workflow to a staging branch first. Inspect the GitHub Actions runner log to confirm that tofu init acquired the DynamoDB lock and read your S3 state bucket without errors.
Before rolling this out across production, complete two essential safeguards:
- Back up remote state: Run
aws s3 cp s3://corp-infrastructure-tfstate-prod/ ./backup-state/ --recursiveto capture an exact snapshot before the first run. - Standardize developer workstations: Have all team members install
tofulocally. If a developer runs a newer proprietary Terraform binary (like Terraform 1.9+) locally, it could advance the state schema version and lock out your OpenTofu pipeline.

