0
0
Terraformcloud~7 mins

Dynamic block syntax in Terraform - Commands & Configuration

Choose your learning style9 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.