๐๏ธ
Terraform
Terraform CLI commands and HCL patterns for infrastructure as code
Core Workflow
The essential init โ plan โ apply โ destroy lifecycle
bashยทInitialize working directory
terraform init
bashยทRe-init and upgrade providers
terraform init -upgrade
bashยทValidate configuration
terraform validate
bashยทFormat all .tf files
terraform fmt -recursive
bashยทPlan changes
terraform plan
bashยทPlan and save to file
terraform plan -out=tfplan
bashยทApply saved plan
terraform apply tfplan
bashยทApply without confirmation prompt
terraform apply -auto-approve
bashยทDestroy all resources
terraform destroy
bashยทDestroy without confirmation prompt
terraform destroy -auto-approve
Targeting & Partial Changes
Apply or destroy specific resources without touching everything
bashยทPlan only a specific resource
terraform plan -target=aws_instance.web
bashยทApply only a specific resource
terraform apply -target=aws_instance.web
bashยทDestroy only a specific resource
terraform destroy -target=aws_instance.web
bashยทTarget a module
terraform apply -target=module.vpc
bashยทReplace (taint) a resource
terraform apply -replace=aws_instance.web
State Management
Inspect, move, import and manipulate Terraform state
bashยทList all resources in state
terraform state list
bashยทShow a specific resource in state
terraform state show aws_instance.web
bashยทMove resource in state (rename)
terraform state mv aws_instance.old aws_instance.new
bashยทRemove resource from state (keep real infra)
terraform state rm aws_instance.web
bashยทPull remote state to stdout
terraform state pull
bashยทPush local state to remote
terraform state push terraform.tfstate
bashยทImport existing resource into state
terraform import aws_instance.web i-1234567890abcdef0
bashยทShow full state as JSON
terraform show -json | jq .
bashยทUnlock stuck state
terraform force-unlock <lock-id>
Variables & Outputs
Pass variables in and read outputs out
bashยทPass variable on CLI
terraform apply -var='instance_type=t3.medium'
bashยทPass variables from file
terraform apply -var-file=prod.tfvars
bashยทShow all outputs
terraform output
bashยทGet a specific output value
terraform output instance_ip
bashยทGet output as raw string (no quotes)
terraform output -raw instance_ip
bashยทGet output as JSON
terraform output -json
hclยทVariable with validation (HCL)
variable "environment" {
type = string
description = "Deployment environment"
default = "dev"
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Must be dev, staging, or prod."
}
}hclยทSensitive output (HCL)
output "db_password" {
value = aws_db_instance.main.password
sensitive = true
}Workspaces
Manage multiple state environments with workspaces
bashยทList workspaces
terraform workspace list
bashยทShow current workspace
terraform workspace show
bashยทCreate workspace
terraform workspace new staging
bashยทSwitch workspace
terraform workspace select prod
bashยทDelete workspace
terraform workspace delete staging
hclยทUse workspace name in config (HCL)
resource "aws_s3_bucket" "data" {
bucket = "my-app-${terraform.workspace}-data"
}Providers & Modules
Lock, install and manage providers and modules
bashยทList installed providers
terraform providers
bashยทLock provider versions
terraform providers lock -platform=linux_amd64 -platform=darwin_arm64
bashยทDownload modules and providers
terraform get
bashยทUpdate modules to latest matching version
terraform get -update
hclยทProvider version constraints (HCL)
terraform {
required_version = ">= 1.6.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}hclยทCall a child module (HCL)
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.1.2"
name = "my-vpc"
cidr = "10.0.0.0/16"
azs = ["us-east-1a", "us-east-1b"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
}Remote Backends
Configure S3 and Terraform Cloud backends for shared state
hclยทS3 backend with DynamoDB locking (HCL)
terraform {
backend "s3" {
bucket = "my-tf-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-lock"
}
}hclยทTerraform Cloud backend (HCL)
terraform {
cloud {
organization = "my-org"
workspaces {
name = "my-app-prod"
}
}
}bashยทMigrate state to new backend
terraform init -migrate-state
bashยทReconfigure backend (skip state migration)
terraform init -reconfigure
Common HCL Patterns
Loops, conditionals, locals and dynamic blocks
hclยทfor_each over a map
variable "buckets" {
default = {
logs = "us-east-1"
backups = "us-west-2"
}
}
resource "aws_s3_bucket" "this" {
for_each = var.buckets
bucket = "my-app-${each.key}"
region = each.value
}hclยทcount with conditional
resource "aws_eip" "nat" {
count = var.environment == "prod" ? 1 : 0
domain = "vpc"
}hclยทlocals block
locals {
common_tags = {
Project = var.project_name
Environment = var.environment
ManagedBy = "terraform"
}
is_prod = var.environment == "prod"
}
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
instance_type = local.is_prod ? "t3.large" : "t3.micro"
tags = local.common_tags
}hclยทdynamic block
variable "ingress_rules" {
default = [
{ port = 80, cidr = "0.0.0.0/0" },
{ port = 443, cidr = "0.0.0.0/0" },
]
}
resource "aws_security_group" "web" {
name = "web-sg"
dynamic "ingress" {
for_each = var.ingress_rules
content {
from_port = ingress.value.port
to_port = ingress.value.port
protocol = "tcp"
cidr_blocks = [ingress.value.cidr]
}
}
}hclยทdepends_on and lifecycle
resource "aws_instance" "app" {
ami = data.aws_ami.ubuntu.id
instance_type = "t3.micro"
depends_on = [aws_iam_role_policy.app]
lifecycle {
create_before_destroy = true
ignore_changes = [ami]
prevent_destroy = true
}
}hclยทData source lookup
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"] # Canonical
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-*-22.04-amd64-server-*"]
}
}
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
instance_type = "t3.micro"
}Debugging & Inspection
Inspect expressions, enable logging and troubleshoot plans
bashยทInteractive console (evaluate expressions)
terraform console
bashยทShow planned changes as JSON
terraform plan -out=tfplan && terraform show -json tfplan | jq .
bashยทEnable detailed logging
TF_LOG=DEBUG terraform apply
bashยทLog to file
TF_LOG=INFO TF_LOG_PATH=./tf.log terraform plan
bashยทGraph resource dependencies
terraform graph | dot -Tsvg > graph.svg
hclยทPrint value during plan with check (HCL)
check "bucket_name_valid" {
assert {
condition = length(var.bucket_name) <= 63
error_message = "S3 bucket name must be 63 characters or fewer."
}
}