Press ESC to close Press / to search

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

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.

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_each with values that are unknown at plan time more gracefully than Terraform.
  • Loopable import blocks: OpenTofu 1.9 adds the ability to use for_each within 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?

Advertisement
🏷️ Tags: IaC 2026 infrastructure as code opentofu opentofu guide terraform alternative
R

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.

🐧 Stay Updated with Linux Tips

Get the latest tutorials, news, and guides delivered to your inbox weekly.

Advertisement

Add Comment


↑