π― Goal: Replace repetitive or verbose logic with 3 expressive patterns β no functions needed.
β Youβll master:
- β Conditional (
condition ? true : false) β Environment-aware configs- β Dynamic blocks β Generate nested configs (security groups, IAM policies)
- β Splat (
[*]) β Extract lists fromcountresources in one line
β Without expressions:
- 10x
ingressblocks for 10 security rulesif env == "prod"logic duplicated across 5 resources- Manual
aws_instance.example[0].id,[1].id,[2].id
β With expressions:
β DRY, readable, and scalable configs β before you learn functions.
| Expression | Syntax | Use Case | When to Use |
|---|---|---|---|
| Conditional | cond ? true_val : false_val |
Toggle values by env/flag | One-off decisions (instance size, tags) |
| Dynamic Block | dynamic "block" { for_each = ... } |
Generate nested blocks (e.g., ingress) |
Variable-length nested configs |
| Splat | resource[*].attr |
Extract lists from count resources |
Feed IDs/IPs to other resources |
π‘ Golden Rule:
βIf youβre repeating a block 3+ times β
dynamicis calling.β
variables.tf)variable "env" {
type = string
default = "dev"
}
variable "instance_count" {
type = number
default = 2
}
# πΉ For Dynamic Blocks: list of security rules
variable "ingress_rules" {
type = list(object({
from_port = number
to_port = number
protocol = string
cidr_blocks = list(string)
description = string
}))
default = [
{
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "HTTP"
},
{
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "HTTPS"
}
]
}
main.tfresource "aws_instance" "app" {
count = var.instance_count
ami = "ami-0c7217cdde317cfec" # Amazon Linux 2
# β
Conditional: dev = t2.micro, prod = t3.medium
instance_type = var.env == "dev" ? "t2.micro" : "t3.medium"
tags = {
Name = "app-${count.index}"
Environment = var.env
}
}
β How it works: