Skip to content
>_devvkit
$devvkit learn --librarie terraform-&-opentofu-guide

Terraform & OpenTofu Guide

[iac][cloud][infrastructure][terraform]
Automation & CI/CD
Install
# Terraform:
brew install terraform
# OpenTofu (OSS fork):
brew install opentofu
# Windows: download from terraform.io/downloads

Terraform lets you describe your entire infrastructure in declarative HCL (HashiCorp Configuration Language) files. `terraform plan` shows what will change, `terraform apply` executes it, `terraform destroy` tears it down. State files track real-world resources.

OpenTofu is the open-source fork of Terraform (after HashiCorp switched to BSL license). It's API-compatible with Terraform providers and modules. Most Terraform code works with OpenTofu without changes — just replace `terraform` with `tofu`.

Modules (`terraform-aws-vpc`) are reusable infrastructure packages. Use remote state (S3 + DynamoDB, or Terraform Cloud) for team collaboration. Terraform workspaces manage multiple environments (dev/staging/prod). GUI: Terraform Cloud, OpenTofu via Terragrunt for DRY configurations.

Basic Workflow

Init, plan, applyCore workflow.
terraform init                          # Download providers
terraform plan -out plan.tfplan         # Preview changes
echo "yes" | terraform apply plan.tfplan
# or:
terraform apply -auto-approve           # Skip confirmation
terraform destroy -auto-approve         # Tear everything down
OpenTofu (same workflow)Drop-in replacement.
# OpenTofu uses identical HCL syntax
# Just replace the command:
tofu init
tofu plan
tofu apply

# Test migration from Terraform:
# 1. Backup .terraform/
# 2. tofu init -migrate-state
# 3. tofu plan  # Should show no changes

Providers

AWS EC2 exampleCreate an EC2 instance.
# main.tf
terraform {
  required_providers {
    aws = { source = "hashicorp/aws", version = "~> 5.0" }
  }
}

provider "aws" {
  region = "us-west-2"
}

resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"

  tags = {
    Name = "HelloWorld"
  }
}
Output valuesExtract resource info.
output "instance_ip" {
  value = aws_instance.web.public_ip
  description = "The public IP of the web server"
}

# After apply:
terraform output instance_ip
terraform output -json

State Management

Remote state (S3)Team state management.
# backend.tf	erraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "prod/terraform.tfstate"
    region         = "us-west-2"
    dynamodb_table = "terraform-locks"  # For state locking
    encrypt        = true
  }
}

# State commands:
terraform state list                    # List all resources
terraform state show aws_instance.web   # Show resource details
terraform state rm aws_instance.web     # Remove from state (not destroy)
terraform import aws_instance.web i-12345  # Import existing resource

Modules

VariablesParameterize configs.
# variables.tf
variable "instance_type" {
  description = "EC2 instance type"
  type        = string
  default     = "t3.micro"
}

variable "environment" {
  type = string
  validation {
    condition     = contains(["dev", "staging", "prod"], var.environment)
    error_message = "Must be dev, staging, or prod."
  }
}

# Use: var.instance_type
# Set: terraform apply -var="instance_type=t3.large"
# Or via terraform.tfvars:
# instance_type = "t3.large"
Module usageReusable infrastructure.
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.0.0"

  name = "my-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["us-west-2a", "us-west-2b"]
  public_subnets  = ["10.0.1.0/24", "10.0.2.0/24"]
  private_subnets = ["10.0.10.0/24", "10.0.20.0/24"]

  enable_nat_gateway = true
  tags = { Environment = "dev" }
}

Workspaces

WorkspacesMultiple environments.
terraform workspace new dev
terraform workspace new staging
terraform workspace new prod
terraform workspace select dev

# Use in config:
resource "aws_instance" "web" {
  tags = { Environment = terraform.workspace }
}

# Different variable files per workspace:
terraform apply -var-file="dev.tfvars"
terraform apply -var-file="prod.tfvars"