OpenTofu 1.9 Complete Guide: Open Source Terraform Alternative for Infrastructure as Code
π― Key Takeaways
- Why OpenTofu Was Created: The HashiCorp BSL Story
- Differences from Terraform
- Installing OpenTofu on Linux
- Basic HCL Syntax
- Writing Your First OpenTofu Configuration
π Table of Contents
- Why OpenTofu Was Created: The HashiCorp BSL Story
- Differences from Terraform
- Installing OpenTofu on Linux
- Basic HCL Syntax
- Writing Your First OpenTofu Configuration
- State Management
- Migrating from Terraform to OpenTofu
- New Features in OpenTofu 1.9
- Workspaces
- OpenTofu Modules: Reusable Infrastructure Components
- OpenTofu in CI/CD Pipelines
- OpenTofu vs Terraform: Making the Right Choice
In August 2023, HashiCorp made a decision that sent shockwaves through the infrastructure-as-code community: they changed Terraform’s license from the open source Mozilla Public License 2.0 to the Business Source License (BSL) 1.1. The BSL is not an open source license β it restricts use of the software by competitors of HashiCorp. For organizations using Terraform internally to manage their own infrastructure, the practical impact was initially unclear, but the signal was unmistakable: Terraform’s future as a community-owned tool was uncertain.
π Table of Contents
- Why OpenTofu Was Created: The HashiCorp BSL Story
- Differences from Terraform
- Installing OpenTofu on Linux
- Basic HCL Syntax
- Writing Your First OpenTofu Configuration
- State Management
- Migrating from Terraform to OpenTofu
- New Features in OpenTofu 1.9
- Workspaces
- OpenTofu Modules: Reusable Infrastructure Components
- Creating a Reusable Module
- Using the Module
- OpenTofu in CI/CD Pipelines
- OpenTofu vs Terraform: Making the Right Choice
The response from the community was swift. A coalition of companies including Gruntwork, Spacelift, Harness, env0, and others signed the OpenTF Pledge, committing to fork Terraform and maintain it as a genuinely open source tool. The fork was named OpenTofu, and it was donated to the Linux Foundation, ensuring its governance would be independent of any single vendor. OpenTofu 1.9 is the current stable release as of early 2026, and it has moved well beyond being a simple Terraform fork β it now includes features that Terraform has not shipped.
Why OpenTofu Was Created: The HashiCorp BSL Story
Understanding why OpenTofu exists helps you understand its values and direction. The Linux Foundation’s stewardship means the project is governed by a Technical Steering Committee with representation from multiple companies and individual contributors. No single vendor can relicense the code or change the governance rules unilaterally. For organizations that treat infrastructure tooling as critical business infrastructure, this governance model is a meaningful advantage over vendor-controlled alternatives.
OpenTofu maintains close compatibility with Terraform’s HCL syntax and state format, making migration feasible for most users. The team has also committed to never relicensing under a non-open-source license.
Differences from Terraform
For day-to-day use, OpenTofu and Terraform are extremely similar. The HCL configuration syntax is identical. The provider ecosystem is the same (Terraform providers work with OpenTofu). State file format is compatible. The main differences as of OpenTofu 1.9 vs Terraform 1.x are:
- State encryption: OpenTofu 1.7+ added native state file encryption at rest, a long-requested feature not present in open source Terraform.
- Provider-defined functions: OpenTofu 1.7+ allows providers to define custom functions callable in HCL configurations.
- Improved for_each with unknown values: OpenTofu handles
for_eachwith values that are unknown at plan time more gracefully than Terraform. - Loopable import blocks: OpenTofu 1.9 adds the ability to use
for_eachwithin import blocks, dramatically simplifying bulk imports of existing infrastructure. - Governance: OpenTofu is Linux Foundation governed and MPL 2.0 licensed. Terraform is BSL licensed.
Installing OpenTofu on Linux
OpenTofu provides several installation methods. The official installer script is the simplest:
# Download and run the installer
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 standalone
# Verify the installation
tofu version
On Ubuntu/Debian via the official APT repository:
# Install dependencies
sudo apt-get install -y apt-transport-https ca-certificates gnupg
# Add the OpenTofu GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://get.opentofu.org/opentofu.gpg |
sudo gpg --dearmor -o /etc/apt/keyrings/opentofu.gpg
sudo chmod a+r /etc/apt/keyrings/opentofu.gpg
# Add the repository
echo
"deb [signed-by=/etc/apt/keyrings/opentofu.gpg] https://packages.opentofu.org/opentofu/tofu/any/ any main" |
sudo tee /etc/apt/sources.list.d/opentofu.list > /dev/null
# Install OpenTofu
sudo apt-get update
sudo apt-get install -y opentofu
tofu version
On Fedora/RHEL:
sudo dnf config-manager --add-repo https://packages.opentofu.org/opentofu/tofu/rpm_any/rpm_any.repo
sudo dnf install opentofu
tofu version
Basic HCL Syntax
OpenTofu uses HashiCorp Configuration Language (HCL), a declarative language designed to be human-readable. Here are the fundamental constructs:
# Variables
variable "region" {
description = "AWS region to deploy into"
type = string
default = "us-east-1"
}
# Local values
locals {
environment = "production"
common_tags = {
Environment = local.environment
ManagedBy = "opentofu"
}
}
# Output values
output "instance_ip" {
description = "The public IP of the instance"
value = aws_instance.web.public_ip
}
Writing Your First OpenTofu Configuration
Let us build a practical example using the local provider (no cloud credentials required) to demonstrate the workflow:
# main.tf
terraform {
required_version = ">= 1.8.0"
required_providers {
local = {
source = "hashicorp/local"
version = "~> 2.5"
}
}
}
variable "app_name" {
type = string
default = "myapp"
}
variable "environments" {
type = list(string)
default = ["dev", "staging", "production"]
}
resource "local_file" "config" {
for_each = toset(var.environments)
filename = "${path.module}/configs/${each.key}.conf"
content = <<-EOT
APP_NAME=${var.app_name}
ENVIRONMENT=${each.key}
MANAGED_BY=opentofu
EOT
}
output "created_files" {
value = [for f in local_file.config : f.filename]
}
Run the standard OpenTofu workflow:
# Initialize (downloads providers)
tofu init
# See what will be created
tofu plan
# Apply the configuration
tofu apply
# When prompted, type 'yes' or use -auto-approve for automation
tofu apply -auto-approve
# View outputs
tofu output
# Destroy resources when done
tofu destroy
State Management
OpenTofu, like Terraform, stores a state file that maps your configuration to real-world resources. By default, this is stored locally as terraform.tfstate. For team use, you need remote state storage:
# backend.tf - S3 backend example (works with AWS, MinIO, etc.)
terraform {
backend "s3" {
bucket = "my-opentofu-state"
key = "production/main.tfstate"
region = "us-east-1"
dynamodb_table = "opentofu-state-lock"
encrypt = true
}
}
OpenTofu 1.7+ added native state encryption, which can be configured without relying on backend-level encryption:
# State encryption configuration (OpenTofu 1.7+)
terraform {
encryption {
key_provider "pbkdf2" "my_passphrase" {
passphrase = var.state_passphrase
}
method "aes_gcm" "default_method" {
keys = key_provider.pbkdf2.my_passphrase
}
state {
method = method.aes_gcm.default_method
}
}
}
Migrating from Terraform to OpenTofu
If you are migrating an existing Terraform project to OpenTofu, the process is straightforward because OpenTofu is state-compatible with Terraform:
# Step 1: Install OpenTofu alongside Terraform (both can coexist)
tofu version
terraform version
# Step 2: In your existing Terraform project directory
# Run tofu init - it will read your existing .terraform directory
tofu init
# Step 3: Run tofu plan to verify OpenTofu sees the same state
# This should show no changes if your code is compatible
tofu plan
# Step 4: If plan shows no changes, you are ready to switch
# Remove the Terraform lock file and reinitialize
rm .terraform.lock.hcl
tofu init
# Step 5: Run apply to update the lock file with OpenTofu providers
tofu apply
For most standard Terraform configurations, migration requires zero code changes. The only exceptions are configurations that rely on Terraform-specific features that OpenTofu has not yet implemented (very rare) or configurations using HashiCorp’s commercial Terraform Cloud features.
New Features in OpenTofu 1.9
OpenTofu 1.9 introduces loopable import blocks, which is one of the most practically useful new features in recent releases. Previously, importing existing infrastructure into OpenTofu state required separate import blocks for each resource:
# Old way - one import block per resource
import {
to = aws_instance.web_1
id = "i-1234567890abcdef0"
}
import {
to = aws_instance.web_2
id = "i-0987654321fedcba0"
}
# New in OpenTofu 1.9 - loop over a map
locals {
instances = {
web_1 = "i-1234567890abcdef0"
web_2 = "i-0987654321fedcba0"
web_3 = "i-abcdef1234567890a"
}
}
import {
for_each = local.instances
to = aws_instance.web[each.key]
id = each.value
}
This is a significant quality-of-life improvement for teams that are incrementally importing large existing cloud environments into infrastructure-as-code management.
Workspaces
OpenTofu workspaces allow you to maintain multiple state files from the same configuration, useful for managing multiple environments:
# Create workspaces
tofu workspace new development
tofu workspace new staging
tofu workspace new production
# List workspaces
tofu workspace list
# Switch to a workspace
tofu workspace select production
# Use the workspace name in your configuration
resource "aws_instance" "web" {
instance_type = terraform.workspace == "production" ? "t3.medium" : "t3.micro"
# ...
}
OpenTofu 1.9 is a mature, production-ready infrastructure-as-code tool that offers genuine advantages over Terraform in governance, licensing, and in certain features like state encryption and loopable imports. For new projects, it is the default recommendation for any organization that values true open source licensing. For existing Terraform users, the migration path is low-risk and the benefit of decoupling from HashiCorp’s licensing decisions is substantial.
OpenTofu Modules: Reusable Infrastructure Components
Modules are the primary mechanism for code reuse in OpenTofu. A module is a directory containing .tf files that encapsulates a logical component of your infrastructure. Well-designed modules let you define infrastructure once and use it consistently across multiple projects and environments.
Creating a Reusable Module
Let’s create a module for a standard web server deployment:
# Directory structure:
# modules/
# web-server/
# main.tf
# variables.tf
# outputs.tf
# modules/web-server/variables.tf
variable "server_count" {
description = "Number of web servers to create"
type = number
default = 2
validation {
condition = var.server_count >= 1 && var.server_count <= 10
error_message = "Server count must be between 1 and 10."
}
}
variable "environment" {
description = "Deployment environment (dev, staging, prod)"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}
variable "instance_type" {
description = "Server instance type"
type = string
default = "t3.micro"
}
# modules/web-server/outputs.tf
output "server_ids" {
description = "IDs of created servers"
value = [for s in local_file.server_config : s.id]
}
output "server_count" {
description = "Number of servers created"
value = var.server_count
}
Using the Module
# main.tf - using the module
module "production_web" {
source = "./modules/web-server"
server_count = 3
environment = "prod"
instance_type = "t3.large"
}
module "staging_web" {
source = "./modules/web-server"
server_count = 1
environment = "staging"
instance_type = "t3.micro"
}
# Access module outputs
output "prod_server_ids" {
value = module.production_web.server_ids
}
OpenTofu in CI/CD Pipelines
Automating infrastructure changes through CI/CD is a best practice that prevents configuration drift and ensures changes are reviewed before being applied. Here is a complete GitHub Actions workflow for OpenTofu:
# .github/workflows/tofu.yml
name: OpenTofu CI/CD
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
validate:
name: Validate and Plan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup OpenTofu
uses: opentofu/setup-opentofu@v1
with:
tofu_version: "1.9.0"
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: OpenTofu Init
run: tofu init
- name: OpenTofu Validate
run: tofu validate
- name: OpenTofu Format Check
run: tofu fmt -check
- name: OpenTofu Plan
run: tofu plan -out=tfplan
env:
TF_VAR_environment: production
- name: Upload Plan
uses: actions/upload-artifact@v4
with:
name: tfplan
path: tfplan
apply:
name: Apply Changes
runs-on: ubuntu-latest
needs: validate
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
environment: production # Requires manual approval in GitHub
steps:
- uses: actions/checkout@v4
- name: Setup OpenTofu
uses: opentofu/setup-opentofu@v1
with:
tofu_version: "1.9.0"
- name: Download Plan
uses: actions/download-artifact@v4
with:
name: tfplan
- name: OpenTofu Apply
run: tofu apply -auto-approve tfplan
The key security element in this workflow is the environment: production setting on the apply job. In GitHub Actions, environments can require manual approval from designated reviewers before the job runs. This creates a human gate between planning and applying infrastructure changes, which is essential for production deployments.
OpenTofu vs Terraform: Making the Right Choice
For teams already using Terraform, the migration path to OpenTofu is straightforward. OpenTofu maintains compatibility with Terraform configurations up to version 1.5, meaning most existing HCL code works without modification. The migration primarily involves changing the CLI binary from terraform to tofu and updating CI/CD pipelines accordingly.
OpenTofu is the better choice in several scenarios. If your organization has concerns about HashiCorp's BSL license and its restrictions on building commercial products that compete with Terraform, OpenTofu resolves that concern entirely. If you want access to features like native state encryption without paying for Terraform Enterprise, OpenTofu provides them in the open source release. If you value Linux Foundation governance and community-driven development over a single vendor's roadmap, OpenTofu's structure is more aligned with those values.
Terraform remains a reasonable choice if your organization has existing Terraform Cloud or Terraform Enterprise contracts, since tight integration with those commercial offerings works best with the official Terraform binary. However, for new projects and greenfield deployments, OpenTofu offers a fully open alternative that is growing rapidly in features and community support.
The infrastructure as code landscape has settled into a clear consensus around HCL as the configuration language for declarative infrastructure. Whether you choose OpenTofu or Terraform, you are using the same language and the same provider ecosystem. The tooling choice primarily affects governance, licensing, and access to specific features, not the day-to-day experience of writing and applying infrastructure configurations.
Was this article helpful?
About Ramesh Sundararamaiah
Red Hat Certified Architect
Expert in Linux system administration, DevOps automation, and cloud infrastructure. Specializing in Red Hat Enterprise Linux, CentOS, Ubuntu, Docker, Ansible, and enterprise IT solutions.