Complete AI Training
Sign inBecome a member

Your job's AI kit

Get your AI kit

Tell us who you are and what you do. We show you your kit right away and email you the link: skills, prompts, AI agents, MCP servers and courses for your job.

500+ jobs ready, and we make a kit for any other job. No payment needed to look.

Share

Skill · DevOps

Opentofu migration

Migrate from Terraform to OpenTofu with state compatibility, provider registry setup, and CI/CD pipeline updates. Use when adopting the open-source Terraform fork or evaluating license-free IaC.

Agentic Awesome SkillsLicense: MITAdded Sep 20, 2026
Use it in my AI

How to use it

  1. Start your plan and connect your AI once
  2. Add the skill to your AI, one time only: press Copy skill and paste it into your AI's instructions: a project in ChatGPT, Claude or Grok, a Gem in Gemini, an agent in Microsoft 365 Copilot, or a rule in Cursor. It stays there for every new chat. In Kimi, paste it at the start of a new chat.
  3. Ask for the task in your own words, or say it directly:
Use the Opentofu migration skill to help me with this.
SKILL.md

OpenTofu Migration

Migrate infrastructure-as-code from HashiCorp Terraform to the open-source OpenTofu fork.

When to Use This Skill

Use this skill when:

  • Migrating from Terraform to OpenTofu for licensing reasons
  • Setting up a new IaC project and evaluating OpenTofu vs Terraform
  • Updating CI/CD pipelines to use OpenTofu
  • Configuring the OpenTofu provider registry

Prerequisites

  • Existing Terraform codebase (0.13+)
  • OpenTofu CLI installed
  • State backend access (S3, GCS, Azure Blob, etc.)

Install OpenTofu

# macOS
brew install opentofu

# Linux (Debian/Ubuntu)
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 install-opentofu.sh

# Linux (RPM)
./install-opentofu.sh --install-method rpm

# Docker
docker run --rm -v $(pwd):/workspace -w /workspace \
  ghcr.io/opentofu/opentofu:latest init

# Verify installation
tofu --version

Migration Checklist

1. Verify Compatibility

# OpenTofu reads Terraform state files directly — no migration needed
# Check your Terraform version (must be <= 1.6.x for full compat)
terraform version

# Run plan with OpenTofu against existing state
tofu init
tofu plan

2. Replace CLI Commands

TerraformOpenTofu
terraform inittofu init
terraform plantofu plan
terraform applytofu apply
terraform destroytofu destroy
terraform fmttofu fmt
terraform validatetofu validate
terraform statetofu state
terraform importtofu import

3. Update Provider Lock File

# Remove Terraform lock and regenerate for OpenTofu
rm .terraform.lock.hcl
tofu init -upgrade

# Verify providers resolve correctly
tofu providers

4. Update State Backend

State files are compatible — no migration needed. Just verify:

# backend.tf — works identically with OpenTofu
terraform {
  backend "s3" {
    bucket         = "mycompany-tfstate"
    key            = "prod/infrastructure.tfstate"
    region         = "us-east-1"
    dynamodb_table = "terraform-locks"
    encrypt        = true
  }
}
# Verify state access
tofu init
tofu state list

5. Provider Registry

OpenTofu uses its own registry but mirrors most Terraform providers:

# versions.tf
terraform {
  required_version = ">= 1.6.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
    kubernetes = {
      source  = "hashicorp/kubernetes"
      version = "~> 2.25"
    }
    # OpenTofu-specific providers
    random = {
      source  = "hashicorp/random"
      version = "~> 3.6"
    }
  }
}

OpenTofu-Specific Features

State Encryption (Not in Terraform)

# OpenTofu supports native state encryption
terraform {
  encryption {
    key_provider "pbkdf2" "my_key" {
      passphrase = var.state_passphrase
    }
    method "aes_gcm" "encrypt" {
      keys = key_provider.pbkdf2.my_key
    }
    state {
      method   = method.aes_gcm.encrypt
      enforced = true
    }
    plan {
      method   = method.aes_gcm.encrypt
      enforced = true
    }
  }
}

Early Variable/Local Evaluation

# OpenTofu allows variables in backend config and module sources
terraform {
  backend "s3" {
    bucket = var.state_bucket  # Works in OpenTofu, not Terraform
    key    = "${var.project}/terraform.tfstate"
    region = var.aws_region
  }
}

CI/CD Pipeline Updates

GitHub Actions

# .github/workflows/tofu.yml
name: OpenTofu
on:
  pull_request:
    paths: ["infra/**"]
  push:
    branches: [main]
    paths: ["infra/**"]

permissions:
  id-token: write
  contents: read
  pull-requests: write

jobs:
  plan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup OpenTofu
        uses: opentofu/setup-opentofu@v1
        with:
          tofu_version: "1.8.0"

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789:role/tofu-deploy
          aws-region: us-east-1

      - name: Init
        run: tofu init
        working-directory: infra/

      - name: Plan
        id: plan
        run: tofu plan -no-color -out=tfplan
        working-directory: infra/

      - name: Comment PR with plan
        if: github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            const output = `#### OpenTofu Plan
            \`\`\`
            ${{ steps.plan.outputs.stdout }}
            \`\`\``;
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: output.substring(0, 65536)
            });

  apply:
    needs: plan
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - uses: opentofu/setup-opentofu@v1
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789:role/tofu-deploy
          aws-region: us-east-1
      - run: tofu init && tofu apply -auto-approve
        working-directory: infra/

GitLab CI

# .gitlab-ci.yml
stages: [validate, plan, apply]

variables:
  TOFU_VERSION: "1.8.0"

.tofu-base:
  image: ghcr.io/opentofu/opentofu:${TOFU_VERSION}
  before_script:
    - tofu init

validate:
  extends: .tofu-base
  stage: validate
  script:
    - tofu fmt -check
    - tofu validate

plan:
  extends: .tofu-base
  stage: plan
  script:
    - tofu plan -out=tfplan
  artifacts:
    paths: [tfplan]

apply:
  extends: .tofu-base
  stage: apply
  script:
    - tofu apply tfplan
  when: manual
  only: [main]
  dependencies: [plan]

Coexistence Strategy

If you need both tools during migration:

# Use aliases to avoid conflicts
alias tf="terraform"
alias tofu="tofu"

# Or use direnv per-project
# .envrc
export PATH="/opt/opentofu/bin:$PATH"

# Wrapper script for gradual migration
#!/bin/bash
if [ -f ".use-opentofu" ]; then
    exec tofu "$@"
else
    exec terraform "$@"
fi

Troubleshooting

IssueSolution
Provider not foundRun tofu init -upgrade, check registry.opentofu.org
State lock conflictSame as Terraform — check DynamoDB/blob lease
Version constraint errorUpdate required_version to >= 1.6.0
Backend migrationState is compatible — just run tofu init
Missing provider credentialsSame env vars work (AWS_, GOOGLE_, ARM_*)

Related Skills

  • terraform-aws (terraform-aws) — AWS IaC patterns (works with both)
  • terraform-azure (terraform-azure) — Azure IaC patterns
  • terraform-gcp (terraform-gcp) — GCP IaC patterns
  • policy-as-code (policy-as-code) — OPA policy checks for IaC

Limitations

  • Infrastructure commands can disrupt services: confirm target host/scope and have backups/snapshots before mutating state.
  • Docs-only import: upstream scripts and templates not bundled.