0
0
Terraformcloud~10 mins

Nested dynamic blocks in Terraform - Commands & Configuration

Choose your learning style9 modes available
Introduction
Sometimes you need to create multiple layers of repeated configuration in Terraform. Nested dynamic blocks let you generate these layers automatically, so you don't have to write repetitive code by hand.
When you want to create multiple nested resources or settings that depend on lists or maps.
When your infrastructure has complex repeating patterns, like multiple security rules inside multiple firewall rules.
When you want to keep your Terraform code clean and avoid copy-pasting similar blocks.
When you need to generate nested blocks dynamically based on variable input.
When you want to manage complex cloud resources with many nested options efficiently.
Config File - main.tf
main.tf
variable "firewalls" {
  type = list(object({
    name  = string
    rules = list(object({
      protocol = string
      ports    = list(number)
    }))
  }))
  default = [
    {
      name = "fw1"
      rules = [
        { protocol = "tcp", ports = [80, 443] },
        { protocol = "udp", ports = [53] }
      ]
    },
    {
      name = "fw2"
      rules = [
        { protocol = "tcp", ports = [22] }
      ]
    }
  ]
}

resource "example_firewall" "firewall" {
  for_each = { for fw in var.firewalls : fw.name => fw }

  name = each.key

  dynamic "rule" {
    for_each = each.value.rules
    content {
      protocol = rule.value.protocol

      dynamic "port" {
        for_each = rule.value.ports
        content {
          number = port.value
        }
      }
    }
  }
}

This Terraform file defines a variable firewalls which is a list of firewall objects. Each firewall has a name and a list of rules. Each rule has a protocol and a list of ports.

The example_firewall resource uses for_each to create one resource per firewall.

Inside the resource, a dynamic "rule" block creates multiple rule blocks based on the rules list.

Inside each rule block, another dynamic "port" block creates multiple port blocks for each port number.

This nested dynamic block structure lets Terraform generate complex nested configurations automatically.

Commands
Initialize Terraform to download providers and prepare the working directory.
Terminal
terraform init
Expected OutputExpected
Initializing the backend... Initializing provider plugins... - Finding latest version of hashicorp/example... - Installing hashicorp/example v1.0.0... - Installed hashicorp/example v1.0.0 (signed by HashiCorp) Terraform has been successfully initialized!
Show the execution plan to see what resources Terraform will create based on the nested dynamic blocks.
Terminal
terraform plan
Expected OutputExpected
An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # example_firewall.firewall["fw1"] will be created + resource "example_firewall" "firewall" { + name = "fw1" + rule { + protocol = "tcp" + port { + number = 80 } + port { + number = 443 } } + rule { + protocol = "udp" + port { + number = 53 } } } # example_firewall.firewall["fw2"] will be created + resource "example_firewall" "firewall" { + name = "fw2" + rule { + protocol = "tcp" + port { + number = 22 } } } Plan: 2 to add, 0 to change, 0 to destroy.
Apply the planned changes to create the firewall resources with nested rules and ports.
Terminal
terraform apply -auto-approve
Expected OutputExpected
example_firewall.firewall["fw1"]: Creating... example_firewall.firewall["fw2"]: Creating... example_firewall.firewall["fw1"]: Creation complete after 2s [id=fw1] example_firewall.firewall["fw2"]: Creation complete after 1s [id=fw2] Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
-auto-approve - Skip interactive approval prompt
Display the current state of the created resources to verify nested dynamic blocks were applied correctly.
Terminal
terraform show
Expected OutputExpected
resource "example_firewall" "firewall" { id = "fw1" name = "fw1" rule { protocol = "tcp" port { number = 80 } port { number = 443 } } rule { protocol = "udp" port { number = 53 } } } resource "example_firewall" "firewall" { id = "fw2" name = "fw2" rule { protocol = "tcp" port { number = 22 } } }
Key Concept

If you remember nothing else from this pattern, remember: nested dynamic blocks let you generate multiple layers of repeated configuration automatically from complex input data.

Common Mistakes
Using a static block instead of dynamic inside another dynamic block
Terraform will not repeat the inner block for each item, so nested lists won't be created properly.
Use a dynamic block inside the outer dynamic block to loop over the nested list.
Not using for_each with a map or list for the outer resource
Terraform cannot create multiple resources from a list without for_each or count, so only one resource is created.
Use for_each with a map or list to create one resource per item.
Referencing the wrong variable inside nested dynamic blocks
Terraform will fail or produce incorrect configuration because the inner dynamic block needs to use the correct nested value.
Use the correct iterator variable names like rule.value and port.value inside nested dynamic blocks.
Summary
Define complex nested input data using variables with lists and objects.
Use for_each on resources to create multiple instances from input data.
Use nested dynamic blocks to generate multiple layers of repeated configuration automatically.