How to Use OpenTofu: The Beginner's Guide (First Install, First main.tf, Plan-Before-Apply, and the Terraform Question)
CodexFuse Team · 2026-10-31T04:24:34.249Z · 12 min read
Learn how to use OpenTofu: install the tofu CLI, write your first main.tf, run init, plan, and apply — plus state encryption and the Terraform fork story.
Learning how to use OpenTofu is the fastest way to manage cloud infrastructure with an IaC tool that is guaranteed to stay open source. OpenTofu is the Linux Foundation's fork of Terraform, created after HashiCorp moved Terraform to the Business Source License (BSL) in 2023; it is licensed under MPL 2.0, joined the CNCF as a sandbox project in April 2025, and runs the same HCL, providers, and state format as Terraform — the binary is just called tofu instead of terraform. This OpenTofu tutorial walks the complete beginner arc: why the fork exists, the first install on your machine, your first main.tf, the init → plan → apply rhythm, built-in state encryption, modules, and the honest OpenTofu vs Terraform answer.
What Is OpenTofu, and Why Did the Community Fork Terraform?
OpenTofu is a community-maintained, Linux Foundation-hosted fork of Terraform that keeps the classic IaC workflow — declare infrastructure in HCL, preview it with plan, create it with apply — under the truly open-source Mozilla Public License 2.0. The fork happened in 2023, after HashiCorp changed Terraform's license from MPL 2.0 to the Business Source License (BSL), a source-available license that is not OSI-approved; vendors and community members started OpenTofu from the last MPL-licensed Terraform 1.5.x codebase so the ecosystem would always have an open home.
Since then OpenTofu has become a project in its own right. It is governed under the Linux Foundation, entered the Cloud Native Computing Foundation as a sandbox project in April 2025, and had crossed 10 million GitHub downloads by December 2025, according to independent industry coverage. The current stable release is v1.13.2, published October 21, 2026, with a 1.12.x maintenance line alongside it — both confirmed against the project's GitHub releases API at write time.
Crucially for beginners, everything you type looks like Terraform. OpenTofu reads the same HCL, uses the same providers, writes the same state file format, and even keeps the terraform block name in configuration files for backward compatibility — only the CLI binary changed names. If you already write HCL, CodexFuse's Terraform plan-preview tool lets you paste HCL and preview a plan without running anything, which is a handy syntax sanity check before you install the CLI for real.
How Do You Use OpenTofu for the First Time?
Use this six-step arc — the complete OpenTofu for beginners path from download to your first resource, and it takes about fifteen minutes on a normal machine.
- Install the
tofubinary. Pick ONE install method (the table below) and use only it. Mixing installers is the top reason beginners end up with two versions fighting on PATH. - Verify it. Run
tofu version. You should seeOpenTofu v1.13.2or later — this confirms the binary works before you write anything. - Write your first main.tf. Three blocks: a
terraformblock naming your providers, a provider block configuring one, and oneresourceblock declaring a single object. The worked example is in the next section. - Run
tofu init. This downloads the provider plugins and sets up your working directory. It is the only command that reaches out to a registry. - Run
tofu planand READ it. The plan shows exactly what will be created, changed, or destroyed —+creates,~modifies,-deletes. The plan-before-apply rule is the one beginner rule that is never optional. - Run
tofu apply, thentofu destroy. Typeyesat the interactive prompt, watch your resource appear, then destroy it to practice the full loop and avoid surprise charges.
How Do You Install OpenTofu on Your Machine?
Pick the row that matches your OS, run its command, and stop there — a second install method on the same machine is how version confusion starts. The official install docs list every method; these are the five a beginner actually needs.
| OS | Method | Command |
|---|---|---|
| macOS or Linux | Homebrew | brew install opentofu |
| Debian / Ubuntu | Official apt repo | 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 |
| Fedora / RHEL | Official rpm repo | ./install-opentofu.sh --install-method rpm |
| Windows | winget | winget install opentofu |
| Any OS | Standalone (no package manager) | ./install-opentofu.sh --install-method standalone — or unzip the release archive from GitHub and move tofu into your PATH |
The Debian path sets up the official packages.opentofu.org repository with two GPG keys (one signs the installer, one signs the repo), then installs the package literally named tofu — not opentofu. The standalone installer verifies what it downloads with cosign or GnuPG; the --skip-verify flag exists for a quick sandbox try, but it is not how you install on a machine you care about.
If you would rather not install anything locally at all, the official OCI image on GitHub Container Registry runs tofu inside a container — our Docker beginner guide covers the runtime side of that route.
What Does Your First main.tf Look Like?
Your first main.tf has three blocks: a terraform block naming your providers, a provider block configuring one, and one resource block declaring a single cloud object. Yes, the block is still called terraform — OpenTofu kept the name deliberately so existing configurations work unchanged; you do not rename it to tofu.
This first project uses the random provider, so you can practice the full loop with no cloud account and no charges:
terraform {
required_providers {
random = {
source = "registry.opentofu.org/hashicorp/random"
}
}
}
provider "random" {}
resource "random_pet" "server_name" {
length = 2
separator = "-"
}
output "server_name" {
value = random_pet.server_name.id
description = "A generated name you can attach to a real resource later."
}
Read it top to bottom. The terraform block declares dependencies and pulls them from the OpenTofu provider registry, which mirrors and extends the provider ecosystem. The resource "random_pet" block declares one object — a short generated name like clever-mongoose. The output block prints the name after every apply, which is how configurations hand values back to you (and to other configurations, later).
What Do tofu init, plan, apply, and destroy Actually Do?
Each command moves one step in the same loop: init prepares, plan previews, apply changes, destroy cleans up — and the plan-before-apply rule is the load-bearing habit that keeps you safe. Most beginners point OpenTofu at a virtual server, so if the target machine concept is new, our what is VPS hosting guide explains exactly the kind of server OpenTofu would provision.
| Command | What it does | Beginner rule |
|---|---|---|
tofu init | Downloads providers, configures the backend, prepares the working directory | Run once per directory; add -upgrade after switching from Terraform or bumping providers |
tofu plan | Dry-run: shows + create, ~ modify, - destroy, with zero changes made | Read every line — never apply a plan you have not reviewed |
tofu apply | Executes the plan after an interactive yes prompt | Use -refresh-only for a state refresh; tofu refresh is deprecated |
tofu destroy | Tears down everything tracked in the state file | Run it on practice projects before you forget and pay for idle resources |
tofu validate | Checks configuration syntax and internal consistency without credentials | Run before every plan — it catches typos for free |
tofu fmt | Rewrites HCL files to canonical style | Run before committing; canonical diffs are reviewable diffs |
Two workflow details matter more than they look. First, tofu plan is the CI/CD habit: teams run plan automatically on every pull request and only apply after a human reads it — that is the same muscle you are building locally. Second, terraform.tfstate is the source of truth mapping your configuration to real objects; OpenTofu reads and writes the same state format as Terraform, which is why an existing remote backend keeps working after a migration. Never commit that file to Git — it contains secrets in plaintext (the next section exists precisely because of this).
How Does OpenTofu State Encryption Work?
Since OpenTofu 1.7, you can encrypt state and plan files at rest with client-side AES-GCM — configured in one block, enforced before anything leaves your machine, and a feature Terraform's open-source CLI never shipped. This is OpenTofu's single clearest technical advantage over Terraform, and it directly fixes the "state file contains database passwords in plaintext" problem.
Encryption is declared inside the terraform block's encryption section with three ingredients: a key_provider that supplies the key, a method (AES-GCM) that uses it, and state/plan links that say where it applies. The key providers are PBKDF2 (passphrase-derived, for local development), AWS KMS, GCP KMS, Azure Key Vault, OpenBao, and an experimental external provider:
terraform {
encryption {
key_provider "pbkdf2" "mykey" {
passphrase = "at-least-16-characters-long"
key_length = 32
iterations = 600000
}
method "aes_gcm" "default" {
keys = key_provider.pbkdf2.mykey
}
state {
method = method.aes_gcm.default
enforced = true # refuse to ever write unencrypted state
}
}
}
Three warnings the official docs insist on. If your project already has unencrypted state, OpenTofu refuses to read it by default (it could have been manipulated) — you add an unencrypted method as a migration step first. If you lose the encryption key, your state is permanently unrecoverable — there is no back door, so keep the key somewhere safer than the state file. And encryption protects state at rest: it does not hide secrets from anyone who can already run tofu on your machine.
How Do You Use OpenTofu Modules?
A module is a folder of .tf files you reuse like a function: you call it with a module block, pass inputs as variables, and read its outputs. Modules are how one-person projects grow into team projects without copy-pasting configuration.
module "network" {
source = "./modules/network"
vpc_name = "prod"
cidr_block = "10.0.0.0/16"
}
The source can be a local path, a Git URL, or a registry address; inputs arrive as declared variables and the module returns declared outputs. Two OpenTofu-specific notes: OpenTofu 1.9 added provider for_each, which makes multi-region module calls dramatically simpler than the old workaround of one provider block per region, and early variable evaluation lets you use variables in places (like backend config) where Terraform historically forced hardcoded values. You can also set the same configuration entirely through the TF_ENCRYPTION environment variable instead of code, which is the friendlier path in CI.
Modules that create servers are the other half of your first real project: once OpenTofu hands you an IP address, you log in with keys — generate a fresh pair with our SSH key generator rather than reusing the key you use everywhere else.
OpenTofu vs Terraform: Which Should a Beginner Pick?
Pick OpenTofu if you want the open-source guarantee; pick Terraform if your job or team needs HashiCorp's commercial ecosystem like Terraform Cloud. The skills transfer either way, because the language is identical — the table is the decision, the four-step migration box is the escape hatch.
| OpenTofu | Terraform (HashiCorp) | |
|---|---|---|
| License | MPL 2.0 — truly open source | BSL 1.1 — source-available, not OSI-approved |
| Governance | Linux Foundation; CNCF sandbox since April 2025 | HashiCorp, now under IBM |
| CLI binary | tofu | terraform |
| Language | Identical HCL — same syntax, same providers, same state format | |
| File names | main.tf, terraform.tfvars, .terraform.lock.hcl, terraform.tfstate — all work in both | |
| State encryption | Built-in client-side AES-GCM since v1.7 | Relies on backend-level encryption only |
| Exclusive features | Provider for_each (v1.9), early variable evaluation, -exclude flag, native S3 locking without DynamoDB | Terraform Cloud/Enterprise ecosystem, deepest commercial tooling |
Migrating from Terraform takes four steps, and the third is the proof it worked: back up terraform.tfstate first; install the tofu binary; run tofu init -upgrade in your project directory; then run tofu plan and confirm it shows zero changes — that empty plan is OpenTofu proving your configuration and state moved over untouched, and only then do you run tofu apply. One caution on a shortcut you will see in forums: alias terraform='tofu' is a migration aid for existing muscle memory, not something to set on a fresh machine — new setups should learn the real command name.
Beginner Mistakes to Avoid
| Mistake | What happens | Do this instead |
|---|---|---|
Committing terraform.tfstate to Git | Secrets in plaintext become repo history forever | .gitignore it on day one; use a remote backend plus state encryption |
| Applying without reading the plan | - lines delete real infrastructure | Read every plan; in teams, require plan review on pull requests |
| Mixing install methods | Two tofu versions fight on PATH | Pick one method and uninstall the other |
| Hand-editing cloud resources, then re-planning | OpenTofu detects drift and tries to revert your clicks | Change infrastructure in code only — the console is read-only for managed resources |
Forgetting tofu destroy on practice projects | Idle cloud resources keep billing | Destroy at the end of every practice session |
| Losing the encryption passphrase | State becomes permanently unreadable | Store the key in a password manager or KMS — never only in your shell history |
Sources
- OpenTofu official install docs, opentofu.org/docs/intro/install — install methods, Debian repo steps, installer script, OCI image; crawled 2026-10-31
- OpenTofu official State and Plan Encryption docs, opentofu.org/docs/language/state/encryption — key providers, AES-GCM, unencrypted migration method, TF_ENCRYPTION variable; crawled 2026-10-31
- GitHub opentofu/opentofu releases API — v1.13.2 released 2026-10-21 (latest), v1.12.11 maintenance release 2026-10-29; fetched 2026-10-31
- Scalr, "What Is OpenTofu? 2026 Guide to the Open-Source Terraform Fork" — MPL 2.0, Linux Foundation governance, CNCF sandbox April 2025, unique features (state encryption v1.7, provider for_each v1.9, -exclude flag), migration steps; via fresh SERP 2026-10-31
- DZone, "Deploying Infrastructure With OpenTofu" — install arc, first main.tf tutorial, winget on Windows, state file explanation; via fresh SERP 2026-10-31
- Spacelift, "OpenTofu Cheat Sheet: 32 CLI Commands You Should Know" — init/plan/apply/destroy/validate/fmt semantics, tofu refresh deprecated in favor of apply -refresh-only; via fresh SERP 2026-10-31
- Spacelift, "OpenTofu State File Encryption Overview" — six key providers (PBKDF2, AWS KMS, GCP KMS, Azure Key Vault, OpenBao, external), enforced mode; via fresh SERP 2026-10-31
- tech-insider.org, "OpenTofu vs Terraform vs Pulumi (2026)" — fork from Terraform 1.5.x codebase, state-file compatibility, migration steps; via fresh SERP 2026-10-31
- cloudandclear.uk, "OpenTofu Enterprise Guide: Greenfield IaC in 2026" — 10M+ GitHub downloads by December 2025, CNCF sandbox April 2025, native S3 locking via use_lockfile; via fresh SERP 2026-10-31
- Pigsty docs, "OpenTofu" quick start — backward-compatible file names (terraform/, .tf, terraform.tfvars, .terraform.lock.hcl, terraform.tfstate); via fresh SERP 2026-10-31
Frequently Asked Questions
Is OpenTofu really free and open source?
Yes. OpenTofu is licensed under the Mozilla Public License 2.0, developed in the open under the Linux Foundation, and accepted into the CNCF as a sandbox project in April 2025. It was created specifically so the IaC ecosystem would keep a genuinely open-source home after Terraform's 2023 move to the Business Source License — that guarantee is written into its governance, not just its marketing.
Can OpenTofu use my existing Terraform files?
Yes — that is the whole point of the fork. OpenTofu reads the same HCL, uses the same providers, and writes the same state format; your main.tf, terraform.tfvars, and lock files work unchanged. Back up your state, run tofu init -upgrade, and confirm tofu plan shows zero changes before your first apply.
Should I learn OpenTofu or Terraform first as a beginner?
Learn the language once and you know both — the HCL syntax, provider model, and plan/apply workflow are identical. Choose OpenTofu for the open-source guarantee and its extras (state encryption, provider for_each); choose Terraform if your employer or clients standardize on Terraform Cloud. Nothing you learn is wasted either way.
What is the one rule OpenTofu beginners must never break?
Plan before apply, every time. tofu plan is free and safe; tofu apply changes real infrastructure. The plan's - (destroy) lines are the ones that bite — read them twice, especially on your first month.
Does OpenTofu encrypt state files?
Yes — since v1.7, OpenTofu ships built-in client-side state and plan encryption with AES-GCM, which Terraform's open-source CLI never had. Pick a key provider (a passphrase via PBKDF2 for local work, a KMS for production), set enforced = true, and guard the key: losing it makes the state permanently unreadable.