What are dynamic blocks, and when are they useful?

4 minadvancedterraformdynamic-blockshcl

Quick Answer

A `dynamic` block programmatically generates a variable number of nested configuration blocks (like multiple `ingress` blocks in a security group) by iterating over a list/map, since ordinary nested blocks can't be created with `count`/`for_each` themselves. It's useful when the number of repeated nested blocks depends on input data — e.g., a variable list of firewall rules — but should be used sparingly, since it trades readability for flexibility; when the set of nested blocks is fixed, writing them out explicitly is clearer.

Detailed Answer

count and for_each (from the previous question) let you repeat an entire resource block. dynamic blocks solve a related but different problem: repeating a nested block inside a resource, based on the size of some input data.

The problem it solves

Consider a security group with a variable number of ingress rules:

resource "aws_security_group" "web" {
  name = "web-sg"

  ingress {
    from_port = 80
    to_port   = 80
    protocol  = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  # ...how many more `ingress` blocks do we need? Depends on input data.
}

You can't apply count/for_each directly to the ingress { ... } nested block itself — those meta-arguments only work on top-level resource/module blocks.

The dynamic block

variable "ingress_rules" {
  type = list(object({
    port        = number
    cidr_blocks = list(string)
  }))
}

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_blocks
    }
  }
}

For each element in var.ingress_rules, Terraform generates one ingress { ... } block, with ingress.value referencing the current element (the iterator variable name matches the block label, "ingress", unless overridden with iterator).

When to use it (and when not to)

  • Use it when the number of nested blocks genuinely depends on input data — a variable list of firewall rules, a variable number of load balancer listener rules, etc.
  • Avoid it when the set of nested blocks is fixed and known — writing them out explicitly is more readable and easier to diff in a PR. Dynamic blocks trade some readability for flexibility, so reach for them only when the alternative is truly impractical (e.g., hardcoding a variable-length list).

Interview-ready summary

dynamic blocks are to nested configuration blocks what for_each is to whole resources — a way to generate a variable number of them from a collection, used sparingly because they add a layer of indirection to otherwise-static configuration.

Related Resources