Dynamic Blocks

A dynamic block generates repeated nested blocks, like security group rules, from a collection.

Syntaxdynamic "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, using ingress.value.

Example

Example · hcl
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.

Example · hcl
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.

Example · hcl
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.

Example · hcl
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

  • Be the first to comment on this lesson.