Terraform Language Patterns Cheat Sheet

High-value HCL patterns for variables, locals, outputs, loops, conditionals, dynamic blocks, and data shaping.

View
StandardDetailedCompact
Export
Copy the compact sheet, download it, or print it.
Download
`D` dense toggle · `C` copy all
## Variables, Locals, Outputs
String variable
variable "environment" {
  type        = string
  description = "Deployment environment"
}

# Declare a typed string variable.

Object variable
variable "subnet" {
  type = object({
    cidr = string
    az   = string
  })
}

# Declare a typed object variable.

Locals block
locals {
  common_tags = {
    app         = "web"
    environment = var.environment
  }
}

# Compute reusable values in locals.

Sensitive output
output "db_password" {
  value     = random_password.db.result
  sensitive = true
}

# Mark an output sensitive to reduce accidental display.

## Meta-arguments
Use count
resource "aws_instance" "web" {
  count = 2
  ami   = var.ami_id
  instance_type = "t3.micro"
}

# Create multiple similar resources with count.

Use for_each
resource "aws_s3_bucket" "logs" {
  for_each = toset(["app","elb","audit"])
  bucket   = "${var.prefix}-${each.key}"
}

# Create resources keyed by map/set members.

Explicit dependency
resource "aws_instance" "web" {
  # ...
  depends_on = [aws_internet_gateway.this]
}

# Force resource ordering when dependency is not inferred from arguments.

Lifecycle rules
resource "aws_s3_bucket" "logs" {
  bucket = var.bucket_name
  lifecycle {
    prevent_destroy = true
    ignore_changes  = [tags]
  }
}

# Control replace/delete behavior and ignored drift.

## Expressions and Functions
Conditional expression
instance_type = var.environment == "prod" ? "t3.large" : "t3.micro"

# Choose values conditionally.

For expression
locals {
  private_subnet_ids = [for s in aws_subnet.private : s.id]
}

# Transform collections with a for expression.

Merge maps
locals {
  tags = merge(local.common_tags, { owner = "platform" })
}

# Combine multiple maps into one.

try and can
locals {
  instance_arn = try(aws_instance.web.arn, null)
  has_name     = can(var.config.name)
}

# Handle optional values and guard against invalid access.

templatefile function
user_data = templatefile("${path.module}/user-data.sh.tftpl", {
  environment = var.environment
})

# Render a file template with variables.

## Dynamic Blocks and Data Sources
Dynamic block
dynamic "ingress" {
  for_each = var.ingress_rules
  content {
    from_port   = ingress.value.from_port
    to_port     = ingress.value.to_port
    protocol    = ingress.value.protocol
    cidr_blocks = ingress.value.cidr_blocks
  }
}

# Generate repeated nested blocks from input data.

Data source example
data "aws_ami" "ubuntu" {
  most_recent = true
  owners      = ["099720109477"]

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
  }
}

# Query existing infrastructure data for use in resources.