linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
Intro
Lessons
Footer
linuxlab-TutorialsPricingAboutPrivacy & cookies
Copyright © 2026 LinuxLab. All rights reserved.
linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
  • Introduction
  • Lessons
  • How it works
  • Knowledge base
  • Cheat sheet
  • Capstone
  • Interview prep
home/terraform/lessons/tf-advanced-07-opentofu-matrix

lesson ── terraform-advanced ── ~12 мин ── 6 шагов

OpenTofu, matrix CI alongside Terraform

OpenTofu is a fork of Terraform under MPL-2.0. The tofu binary already sits in the image next to terraform. You run one HCL through both, compare the result, and build a matrix pipeline for CI. This is your insurance against lock-in to the HashiCorp license.

▶ интерактивный sandbox

Поднимется пара контейнеров: terraform 1.9 и localstack 3.8 в одной сети. В браузере откроется терминал, можно сразу terraform init. Каждый шаг проверяется автоматически. TTL 45 минут, без регистрации.

запустить sandbox →

stack ── terraform · localstack · 1 GB RAM · самоуничтожается через 45 мин простоя

Шаги

  1. 01

    OpenTofu in the image

    bash
    which terraform
    terraform --version
    echo ---
    which tofu
    tofu --version

    Both binaries live in /usr/local/bin. The versions may not match, and that is normal: the fork branches develop in parallel.

    ✓ Tofu and terraform live in one sandbox.

  2. 02

    The same HCL, both tools

    bash
    cd /home/student/parity
    cat > main.tf <<'EOF'
    resource "aws_s3_bucket" "parity_demo" {
      bucket = "linuxlab-parity-demo"
      tags = {
        ManagedBy = "either"
      }
    }
    output "name" {
      value = aws_s3_bucket.parity_demo.bucket
    }
    EOF

    First Terraform:

    bash
    terraform init -no-color > /dev/null
    terraform plan -no-color -out=plan.terraform > /dev/null
    terraform show -no-color plan.terraform > plan-terraform.txt
    head -20 plan-terraform.txt

    Now OpenTofu (in a new directory so the state does not get mixed up):

    bash
    mkdir -p tofu-test
    cp main.tf provider.tf tofu-test/
    cd tofu-test
    tofu init -no-color > /dev/null
    tofu plan -no-color -out=plan.tofu > /dev/null
    tofu show -no-color plan.tofu > ../plan-tofu.txt
    cd ..
    head -20 plan-tofu.txt

    Both showed the same resource to create.

    ✓ Both tools see the same thing. Parity confirmed.

  3. 03

    Diff between the plans

    bash
    diff plan-terraform.txt plan-tofu.txt | head -20 || echo "outputs identical (or minor diff)"

    You should get either no output (identical) or a minor stylistic diff (for example, the header "Terraform used the selected providers" vs "OpenTofu used..."). Semantically, the same thing.

    In CI this diff (minus the headers) is checked regularly. If a large diff suddenly appears, a feature has diverged, and it is time to decide which one you pick.

    ✓ The plans are compared. Divergence shows up clearly.

  4. 04

    Matrix CI: a workflow for two

    bash
    mkdir -p .github/workflows
    cat > .github/workflows/parity.yml <<'EOF'
    name: Parity CI
    on:
      push:
        branches: [main]
      pull_request:
    jobs:
      terraform-plan:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - uses: hashicorp/setup-terraform@v3
            with:
              terraform_version: 1.9.8
          - run: terraform init -input=false
          - run: terraform plan -input=false -no-color
      opentofu-plan:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - uses: opentofu/setup-opentofu@v1
            with:
              tofu_version: 1.8.5
          - run: tofu init -input=false
          - run: tofu plan -input=false -no-color
    EOF
    cat .github/workflows/parity.yml

    Two independent jobs. If one is green and the other is red, the divergence shows up at once. On a critical divergence the PR is blocked.

    ✓ The matrix workflow is written. On real GitHub both jobs run in parallel.

  5. 05

    State from Terraform, read by OpenTofu

    The most important property, state is compatible.

    bash
    # apply through Terraform
    cd /home/student/parity
    terraform apply -auto-approve plan.terraform > /dev/null
    ls terraform.tfstate
    # OpenTofu can now work with this state
    tofu show terraform.tfstate 2>&1 | head -15

    OpenTofu read the state created by Terraform correctly. This is the basis of the painless migration: you switch CI from terraform to tofu and change nothing else.

    The reverse works too: state from tofu apply is read by terraform.

    ✓ State is fully compatible. Migration in both directions without conversion.

  6. 06

    When terraform, when tofu

    The decision:

    bash
    cat > /tmp/decision.md <<'EOF'
    | Signal | Choice |
    |---|---|
    | Team already on HashiCorp Terraform / HCP | Terraform |
    | New project, no lock-in | OpenTofu (MPL-license) |
    | You need Stacks (HCP) | Terraform |
    | You need state encryption at rest | OpenTofu (native) |
    | You need exclude in for_each | OpenTofu 1.8+ |
    | Team on Atlantis / Spacelift | Check support for both in your tool |
    | Air-gapped / regulated | OpenTofu (Linux Foundation, MPL) |
    For most teams: matrix CI is the insurance, and the default choice
    is set by your current infrastructure and risk tolerance.
    EOF
    cat /tmp/decision.md

    In a real team this is part of an architectural decision; an ADR records it.

    ✓ You know when to use which. Next, the capstone project.

    Migration scenario

    A real Terraform to OpenTofu migration for a team:

    1. Pin the current Terraform (1.5.7, the last MPL one). You can keep working without any tricks.

    2. Install OpenTofu in parallel on dev machines. Run tofu plan on the current stacks, there should be no divergence.

    3. Add matrix CI, tofu plan next to terraform plan. Green, fine, carry on.

    4. Switch in CI. In a single feature branch, swap setup-terraform for setup-opentofu. Test it for a week.

    5. Switch main. Once you have confidence, switch everyone over. State is not touched.

    6. Remove the terraform job a month or two after the state is stable.

    If something breaks, the terraform job is still there, your fallback is ready.

    More on this in tf-opentofu-parity.

    • → OpenTofu in full

Что ты узнал

OpenTofu (tofu) is a drop-in replacement for Terraform. The image already ships it next to terraform. tofu init/plan/apply works with the same HCL and the same state. CI with two jobs (terraform + tofu) catches divergence right away.

команды

  • tofu --versionOpenTofu is preinstalled in the sandbox image.
  • tofu init && tofu planthe usual commands, run through tofu.
  • diff plan.terraform plan.tofucompare the plan output for divergence.

концепции

  • · OpenTofu = MPL fork of the last MPL Terraform
  • · State is compatible, migration without conversion
  • · Divergence grows across versions; matrix CI catches it right away

← предыдущий

OPA + Rego, gating plan.json

следующий →

Data sources: reading what already exists

Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies