OpenTofu Tutorial: Provision Infrastructure as Code
OpenTofu is the open-source, community-governed fork of Terraform. This guide takes you from install to a working init/plan/apply loop and encrypted state.
What is OpenTofu?
OpenTofu is an open-source tool for building, changing, and versioning infrastructure as code. You describe the resources you want - virtual machines, networks, DNS records, Kubernetes objects, SaaS configuration - in declarative configuration files, and OpenTofu figures out how to create, update, or destroy real resources to match that description.
It is a fork of Terraform. When HashiCorp relicensed Terraform under the Business Source License (BUSL) in August 2023, a group of users and vendors forked the last MPL 2.0 version and created OpenTofu. The project was donated to the Linux Foundation and is now developed in the open with a public RFC process and a steering committee, rather than controlled by a single vendor.
For day-to-day work OpenTofu behaves like Terraform: same HCL syntax, same providers, same module ecosystem, same state model. The CLI is invoked as tofu instead of terraform. Since the fork, OpenTofu has added features that Terraform's open-source CLI does not have - the most notable being native state encryption.
How OpenTofu works (key concepts)
A few concepts cover most of what you need:
- Configuration (HCL). You write
.tffiles describingresource,data,variable,output, andproviderblocks. The language is declarative: you state the desired end state, not the steps to get there. - Providers. Plugins that translate HCL into real API calls (AWS, Google Cloud, Azure, Kubernetes, Cloudflare, and hundreds more).
tofu initdownloads the providers your config requires and pins them in a lock file. - State. OpenTofu records the real-world resources it manages in a state file (
terraform.tfstateby default). State maps your config to actual resource IDs and lets OpenTofu compute diffs. State can live locally or in a remote backend (S3, GCS, Azure Blob, and others). - The plan/apply loop.
tofu plancompares desired config against current state and shows what would change.tofu applyexecutes that plan. Nothing mutates infrastructure until you apply. - Dependency graph. OpenTofu builds a graph from references between resources and orders create/update/destroy operations automatically.
The mental model is simple: write config, run plan to preview, run apply to make real infrastructure match the config.
Installing OpenTofu
OpenTofu ships a single static tofu binary. The simplest cross-distro route is the official installer script. Always inspect a script before piping it to a shell.
# Download, inspect, then run the official installer (Debian/Ubuntu .deb method)
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
On macOS or Linux with Homebrew:
brew install opentofu
On any Linux with Snap (note the classic confinement flag):
sudo snap install --classic opentofu
Verify the install and check the version - the binary prints its own version plus any installed providers:
tofu version
# OpenTofu v1.x.y
# on linux_amd64
Hands-on: your first stack with encrypted state
Let's provision something with no cloud account required - a local file - so you can run the full loop end to end, then add OpenTofu's best-known feature, state encryption.
Create main.tf:
terraform {
required_version = ">= 1.7.0"
required_providers {
local = {
source = "hashicorp/local"
version = "~> 2.5"
}
}
# Native state encryption - PBKDF2 key from a passphrase.
encryption {
key_provider "pbkdf2" "passphrase" {
passphrase = "change-me-to-a-long-random-string"
}
method "aes_gcm" "encrypt" {
keys = key_provider.pbkdf2.passphrase
}
state {
method = method.aes_gcm.encrypt
}
}
}
resource "local_file" "hello" {
filename = "${path.module}/hello.txt"
content = "Provisioned by OpenTofu\n"
}
output "file_path" {
value = local_file.hello.filename
}
Now run the standard loop:
tofu init # download the local provider, write the lock file
tofu fmt # canonicalize formatting
tofu validate # static-check the config
tofu plan -out=tfplan # preview: + 1 to add
tofu apply tfplan # create hello.txt and write encrypted state
After apply, inspect the state file. With encryption enabled the file holds an encrypted payload instead of readable resource attributes:
head -c 200 terraform.tfstate # encrypted blob, not plaintext attributes
tofu output file_path # ./hello.txt
cat hello.txt # Provisioned by OpenTofu
State encryption runs client-side before the state is ever written or uploaded to a backend, with key providers such as AWS KMS, GCP KMS, or a PBKDF2 passphrase. Plan for one consequence: Terraform cannot read an encrypted state file, so enabling encryption ties that project to OpenTofu unless you decrypt the state again. In production, source the passphrase from an environment variable or a KMS key provider rather than hard-coding it.
Tear everything down when you are done:
tofu destroy # remove hello.txt and clear state
When to use OpenTofu
Reach for OpenTofu when you want declarative, reviewable, repeatable infrastructure - anything you would otherwise create by hand in a cloud console or with one-off scripts. It fits multi-cloud and multi-provider setups, short-lived environments created per pull request, and any team that wants infrastructure changes to go through plan review in version control.
Choose OpenTofu specifically over Terraform when licensing matters (you need a permissive MPL 2.0, vendor-neutral tool), when you want native state encryption for compliance regimes like HIPAA, SOC 2, or PCI-DSS, or when you want features the Terraform CLI does not have, such as provider for_each and OCI-registry distribution of modules and providers. Because configuration, providers, and state are compatible up to the fork point, migrating an existing Terraform project is often as little as installing tofu and re-running init - test it in a non-production workspace first.
It is more than you need for a single test resource you will delete in five minutes, and it does not replace configuration management inside a running machine (use Ansible, cloud-init, or a container image for that). For the lifecycle of cloud and platform resources, though, OpenTofu is a strong, openly governed default.
Frequently asked questions
What is OpenTofu?
OpenTofu is an open-source infrastructure-as-code tool that provisions and manages cloud resources from declarative configuration. It is a fork of Terraform, created in 2023 after Terraform moved to the BUSL license, and is now governed by the Linux Foundation. Its CLI command is tofu.
Is OpenTofu compatible with Terraform?
Largely yes. OpenTofu uses the same HCL configuration language, the same providers and modules (served through the OpenTofu Registry), and the same state file format. Older Terraform configs and state migrate cleanly. The main one-way exception is OpenTofu's native state encryption, which produces state files Terraform cannot read.
How is OpenTofu different from Terraform?
OpenTofu is MPL 2.0 licensed and community-governed, while Terraform is under the BUSL. OpenTofu has also added features that the Terraform CLI lacks, such as native client-side state encryption, provider iteration with for_each, and OCI registry support for providers and modules.
Do I need to rewrite my Terraform code to use OpenTofu?
Usually not. For configs targeting Terraform 1.5.x and earlier you can typically install tofu, run tofu init, and continue. Review provider version constraints and any features newer than the fork point, then test in a non-production workspace before switching CI.
Do real production work, free. Live cloud workspaces in your browser - every project you complete lands on your portfolio.
Get started - free