Dynamic Blocks
A dynamic block generates repeated nested blocks, like security group rules, from a collection.
Syntax
dynamic "ingress" {
for_each = var.rules
content { ... }
}Some resources contain repeatable nested blocks — a security group can have many ingress rules. A dynamic block generates those nested blocks from a collection instead of writing each by hand.
Anatomy
dynamic "ingress"— the nested block type to generate.for_each— the collection to iterate.content { ... }— the body of each generated block, usingingress.value.
Example
variable "ports" {
type = list(number)
default = [80, 443]
}
resource "aws_security_group" "web" {
name = "web-sg"
dynamic "ingress" {
for_each = var.ports
content {
from_port = ingress.value
to_port = ingress.value
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
}When to use it
- A team generates all ingress rules for a security group from a list variable using a dynamic block, avoiding a separate rule resource for each port.
- A module accepts a list of listener configurations and uses a dynamic block to generate each listener block inside an ALB resource.
- An engineer uses a dynamic block to create EBS volume attachments for an EC2 instance based on a variable list of disk sizes.
More examples
Dynamic ingress rules
Generates one ingress block per port in the list using a dynamic block, replacing three identical hard-coded ingress blocks.
variable "allowed_ports" {
type = list(number)
default = [80, 443, 8080]
}
resource "aws_security_group" "web" {
name = "web-sg"
dynamic "ingress" {
for_each = var.allowed_ports
content {
from_port = ingress.value
to_port = ingress.value
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
}Dynamic block with map
Generates ASG tag blocks from a map using dynamic, ensuring all tags propagate to launched instances without repetition.
locals {
tags = {
Project = "my-app"
Environment = "prod"
Owner = "platform"
}
}
resource "aws_autoscaling_group" "app" {
min_size = 1
max_size = 3
dynamic "tag" {
for_each = local.tags
content {
key = tag.key
value = tag.value
propagate_at_launch = true
}
}
}Nested dynamic blocks
Shows a dynamic block iterating over a list of objects to generate default_action blocks for an ALB listener.
variable "listeners" {
type = list(object({
port = number
protocol = string
}))
default = [
{ port = 80, protocol = "HTTP" },
{ port = 443, protocol = "HTTPS" }
]
}
resource "aws_lb_listener" "app" {
load_balancer_arn = aws_lb.app.arn
dynamic "default_action" {
for_each = var.listeners
content {
type = "forward"
target_group_arn = aws_lb_target_group.app.arn
}
}
}
Discussion