Bird
Raised Fist0
Terraformcloud~7 mins

Dynamic block syntax in Terraform - Commands & Configuration

Choose your learning style10 modes available
Introduction
Sometimes you want to create multiple similar blocks in your Terraform configuration without repeating code. Dynamic blocks let you generate these blocks automatically from a list or map, making your code cleaner and easier to manage.
When you need to create multiple similar nested blocks based on a list of values.
When you want to avoid repeating the same block multiple times with small differences.
When your infrastructure requires variable numbers of sub-resources depending on input.
When you want to keep your Terraform code DRY (Don't Repeat Yourself).
When you want to generate complex nested configurations dynamically.
Config File - main.tf
main.tf
variable "security_group_rules" {
  type = list(object({
    type        = string
    from_port   = number
    to_port     = number
    protocol    = string
    cidr_blocks = list(string)
  }))
  default = [
    {
      type        = "ingress"
      from_port   = 80
      to_port     = 80
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    },
    {
      type        = "ingress"
      from_port   = 443
      to_port     = 443
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    }
  ]
}

resource "aws_security_group" "example" {
  name        = "example-sg"
  description = "Example security group"

  dynamic "ingress" {
    for_each = [for rule in var.security_group_rules : rule if rule.type == "ingress"]
    content {
      from_port   = ingress.value.from_port
      to_port     = ingress.value.to_port
      protocol    = ingress.value.protocol
      cidr_blocks = ingress.value.cidr_blocks
    }
  }
}

This Terraform file defines a variable security_group_rules which is a list of rule objects. The aws_security_group resource uses a dynamic block named ingress to create multiple ingress rules based on the variable. The for_each expression filters only ingress rules and generates one ingress block per rule. Inside content, the properties of each rule are assigned dynamically.

Commands
This command initializes the Terraform working directory. It downloads the AWS provider plugin and prepares the environment for deployment.
Terminal
terraform init
Expected OutputExpected
Initializing the backend... Initializing provider plugins... - Finding latest version of hashicorp/aws... - Installing hashicorp/aws v4.0.0... - Installed hashicorp/aws v4.0.0 (signed by HashiCorp) Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work.
This command shows the changes Terraform will make to create the security group with dynamic ingress rules. It previews the infrastructure without applying it.
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: # aws_security_group.example will be created + resource "aws_security_group" "example" { + description = "Example security group" + id = (known after apply) + name = "example-sg" + ingress { + cidr_blocks = ["0.0.0.0/0"] + from_port = 80 + protocol = "tcp" + to_port = 80 } + ingress { + cidr_blocks = ["0.0.0.0/0"] + from_port = 443 + protocol = "tcp" + to_port = 443 } } Plan: 1 to add, 0 to change, 0 to destroy.
This command applies the planned changes and creates the security group with the dynamic ingress rules automatically without asking for confirmation.
Terminal
terraform apply -auto-approve
Expected OutputExpected
aws_security_group.example: Creating... aws_security_group.example: Creation complete after 2s [id=sg-0123456789abcdef0] Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
→
-auto-approve - Skips interactive approval prompt to apply changes immediately
This command displays the current state of the deployed infrastructure, showing the security group and its dynamically created ingress rules.
Terminal
terraform show
Expected OutputExpected
aws_security_group.example: id = sg-0123456789abcdef0 name = example-sg description = Example security group ingress { from_port = 80 to_port = 80 protocol = tcp cidr_blocks = ["0.0.0.0/0"] } ingress { from_port = 443 to_port = 443 protocol = tcp cidr_blocks = ["0.0.0.0/0"] }
Key Concept

If you remember nothing else from this pattern, remember: dynamic blocks let you create multiple nested blocks automatically from a list or map, avoiding repeated code.

Common Mistakes
Using dynamic block without 'content' block inside it
Terraform requires the 'content' block inside dynamic blocks to define what each generated block contains; missing it causes syntax errors.
Always include a 'content' block inside the dynamic block to specify the block's properties.
Setting for_each to a list that includes items not matching the block type
If for_each includes items that don't match the intended block type, Terraform will create invalid blocks or fail.
Filter the list or map in for_each to include only items relevant to the dynamic block.
Trying to use dynamic blocks for top-level resources instead of nested blocks
Dynamic blocks only work for nested blocks inside resources, not for creating multiple top-level resources.
Use 'for_each' or 'count' at the resource level to create multiple resources, and dynamic blocks for nested blocks.
Summary
Define a variable list or map with the data for the nested blocks you want to create.
Use a dynamic block with for_each to loop over the list and generate one nested block per item.
Inside the dynamic block, use the content block to specify the properties for each generated block.
Run terraform init, plan, and apply to deploy the infrastructure with dynamic nested blocks.
Use terraform show to verify the created resources and their nested blocks.

Practice

(1/5)
1. What is the main purpose of a dynamic block in Terraform?
easy
A. To generate multiple nested blocks from a list or map dynamically
B. To create a new Terraform provider
C. To define variables with default values
D. To execute shell commands during deployment

Solution

  1. Step 1: Understand the role of dynamic blocks

    Dynamic blocks allow repeating nested blocks based on a collection like a list or map.
  2. Step 2: Compare with other options

    Options A, B, and D describe unrelated Terraform features.
  3. Final Answer:

    To generate multiple nested blocks from a list or map dynamically -> Option A
  4. Quick Check:

    Dynamic block = repeated nested blocks [OK]
Hint: Dynamic blocks repeat nested blocks from lists/maps [OK]
Common Mistakes:
  • Confusing dynamic blocks with variable declarations
  • Thinking dynamic blocks create providers
  • Assuming dynamic blocks run commands
2. Which of the following is the correct syntax to start a dynamic block named ingress in Terraform?
easy
A. dynamic ingress { for_each = var.rules content { ... } }
B. dynamic(ingress) { for_each = var.rules content { ... } }
C. dynamic "ingress" { for_each = var.rules content { ... } }
D. dynamic { ingress for_each = var.rules content { ... } }

Solution

  1. Step 1: Recall dynamic block syntax

    The block must be declared as dynamic "block_name" { ... } with quotes around the block name.
  2. Step 2: Check each option

    dynamic "ingress" { for_each = var.rules content { ... } } uses correct syntax with quotes and proper structure; others miss quotes or have wrong syntax.
  3. Final Answer:

    dynamic "ingress" { for_each = var.rules content { ... } } -> Option C
  4. Quick Check:

    Dynamic block syntax requires quotes around block name [OK]
Hint: Use quotes around block name in dynamic block [OK]
Common Mistakes:
  • Omitting quotes around the block name
  • Using parentheses instead of braces
  • Placing block name outside dynamic keyword
3. Given this Terraform snippet:
dynamic "tag" {
  for_each = {"env" = "prod", "team" = "devops"}
  content {
    key   = tag.key
    value = tag.value
  }
}

What will be the result in the generated resource configuration?
medium
A. No tag blocks generated because map keys are strings
B. A single tag block with key and value set to the entire map
C. Syntax error due to incorrect for_each usage
D. Two tag blocks with keys "env" and "team" and their values

Solution

  1. Step 1: Understand for_each with map in dynamic block

    Using a map with for_each creates one nested block per key-value pair.
  2. Step 2: Analyze content block usage

    Inside content, tag.key and tag.value refer to each map entry's key and value, creating two blocks.
  3. Final Answer:

    Two tag blocks with keys "env" and "team" and their values -> Option D
  4. Quick Check:

    Map for_each creates one block per key-value pair [OK]
Hint: Map in for_each creates one block per key-value pair [OK]
Common Mistakes:
  • Thinking only one block is created for whole map
  • Confusing key and value references inside content
  • Assuming syntax error due to map usage
4. Identify the error in this Terraform dynamic block snippet:
dynamic "egress" {
  for_each = var.egress_rules
  content = {
    from_port = egress.value.from
    to_port   = egress.value.to
  }
}
medium
A. The content block should use braces, not an assignment
B. The variable egress is undefined inside the block
C. Missing quotes around "egress" in dynamic block declaration
D. for_each cannot be used with variables

Solution

  1. Step 1: Check dynamic block content syntax

    The content must be a block, not an assignment. It should be content { ... }, not content = { ... }.
  2. Step 2: Verify other parts

    Variable egress is valid as the iterator, quotes are present, and for_each can use variables.
  3. Final Answer:

    The content block should use braces, not an assignment -> Option A
  4. Quick Check:

    content must be a block, not an equals assignment [OK]
Hint: Use content { ... } block, not content = { ... } [OK]
Common Mistakes:
  • Writing content as an assignment instead of a block
  • Assuming iterator variable is undefined
  • Forgetting quotes around dynamic block name
5. You want to create multiple network_interface blocks dynamically in an AWS instance resource using a list of maps with keys device_index and subnet_id. Which dynamic block correctly achieves this?
hard
A. dynamic "network_interface" { for_each = var.interfaces content { device_index = network_interface.value.device_index subnet_id = network_interface.value.subnet_id } }
B. dynamic "network_interface" { for_each = var.interfaces content { device_index = each.value.device_index subnet_id = each.value.subnet_id } }
C. dynamic "network_interface" { for_each = var.interfaces content { device_index = network_interface.device_index subnet_id = network_interface.subnet_id } }
D. dynamic "network_interface" { for_each = var.interfaces content { device_index = network_interface.key.device_index subnet_id = network_interface.key.subnet_id } }

Solution

  1. Step 1: Identify the iterator variable in dynamic block

    Terraform uses each as the iterator inside dynamic blocks for for_each.
  2. Step 2: Check how to access map values

    Use each.value.key_name to access map elements inside content block.
  3. Step 3: Evaluate options

    dynamic "network_interface" { for_each = var.interfaces content { device_index = each.value.device_index subnet_id = each.value.subnet_id } } correctly uses each.value.device_index and each.value.subnet_id. Others incorrectly use network_interface or network_interface.key.
  4. Final Answer:

    dynamic "network_interface" { for_each = var.interfaces content { device_index = each.value.device_index subnet_id = each.value.subnet_id } } -> Option B
  5. Quick Check:

    Use each.value to access map in dynamic block [OK]
Hint: Use each.value inside dynamic content block [OK]
Common Mistakes:
  • Using block name as iterator variable
  • Using .key instead of .value for map access
  • Omitting the each keyword
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard