We use cookies to understand how the site is used and to display ads. Analytics and advertising only run after you accept. You can change your choice anytime. Privacy policy

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, apply· Core 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 example· Create 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 values· Extract 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

Variables· Parameterize 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 usage· Reusable 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

Workspaces· Multiple 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"