Repetitive configurations can quickly clutter your code when you’re managing cloud infrastructure with Terraform. But to be fair, it’s not always your team’s fault, Terraform configuration files are becoming harder to manage and understand.
Terraform Dynamic block helps create reusable nested blocks using loops like for_each. They make your infrastructure code more efficient, cleaner, and scalable. Whether dealing with complex modules or wanting to minimize hardcoding, learning to use dynamic blocks is an essential skill in Terraform.
This is a quick tutorial on everything about Terraform Dynamic Block. Let’s Learn Along!
What Is a Terraform Dynamic Block?

By creating numerous nested blocks, Terraform dynamic blocks—a unique sort of Terraform block—offer the capability of a for expression.
It is frequently necessary to establish infrastructure resources that are identical or comparable. Multiple virtual server instances on a cloud platform like AWS or Azure Terraform, are a common use case. Terraform offers routines like for_each and count to make the deployment of these resources easier and eliminate the need for lengthy blocks of repetitive code.
Teams can also have to set up several duplicate elements in a resource. To eliminate the requirement for numerous duplicate “blocks” of Terraform code, dynamic blocks are utilized inside an infrastructure resource in conjunction with a for_each function.
Get exclusive access to all things tech-savvy, and be the first to receive
the latest updates directly in your inbox.
Here are some scenarios where dynamic blocks are useful:
- Creating several AWS subnets: If you need to set up subnets across various availability zones, instead of writing individual blocks for each subnet, you can utilize a dynamic block to loop through a list of availability zones and create a subnet for each one.
- Configuring security group rules: When dealing with numerous security group rules, dynamic blocks assist in defining and organizing them in a more compact manner.
- Rather than writing each rule individually, you can use a dynamic block to iterate over a list of rules, making the configuration easier.
- Provisioning multiple EC2 instances: If you require several EC2 instances with similar settings but different characteristics (such as tags or instance types), dynamic blocks enable you to manage this effectively.
A Terraform dynamic block offers the following main advantages:
- Speed: The infrastructure can be deployed more rapidly when the code is simplified, both during development and execution.
- Clarity – code written with dynamic blocks is significantly easier to read and comprehend than code written in several blocks of repetitive code.
- Reuse: It can be challenging and time-consuming to copy, paste, and edit lengthy code blocks. To make this process go more quickly, combine variables and parameters with dynamic blocks.
- Reliability is associated with clarity and reusability; simple, readable code is less likely to include errors.
Dynamic Block Syntax Example
Dynamic Block Syntax in Terraform allows for the generation of various configurations depending on input values. The label indicates the type of dynamic block to be created. The for_each statement iterates over a list or map given by var.iterable_variable, producing a block for each element. The iterator serves as an optional name for the current item in the iteration. The content block holds the configuration specifics for each created block.
dynamic "label" {<br> for_each = var.iterable_variable<br> iterator = iterator_name # Optional, defaults to label<br><br> content {<br> # Configuration details for each iteration<br> attribute = iterator_name.value<br> }<br>}
Applications of Dynamic Block Syntax in the Real World
- A data block downloads existing EC2 instances in a real-world scenario and generates a local variable to store the instance IDs.
- Based on the instance IDs of EC2 instances, a dynamic block applies particular EBS configurations to them.
- By repeating over the instance IDs, various EBS volumes are dynamically attached to the designated instances. This method guarantees that every instance obtains the appropriate EBS volume settings without the need for further code.
Here is an example of how our resource block will look:
resource "aws_instance" "dynamic_instance" {
for_each = {
for instance_id in local.instance_ids :
instance_id => instance_id
}
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
Name = each.key
}
dynamic "ebs_block_device" {
for_each = [
for id in local.instance_ids : id
if id == "i-0d5933a76d45a6aee"
]
content {
device_name = "/dev/sdh"
volume_size = 10
encrypted = true
}
}
dynamic "ebs_block_device" {
for_each = [
for id in local.instance_ids : id
if id == "i-095aff1e2acc82958"
]
content {
device_name = "/dev/sdh"
volume_size = 20
encrypted = true
}
}
}
Required Attribute of Dynamic Block in Terraform
Essential Features of a Dynamic Block
For proper functionality, a dynamic block must include:
- for_each: Loops through a list or map.
- content: The specific content of the block for each iteration.
Additionally, there are optional attributes that can be beneficial:
- iterator: Enables you to change the name of the loop variable from the default ‘each’.
Example:
variable "security_groups" {
default = ["sg-123", "sg-456"]
}
resource "aws_instance" "web" {
ami = "ami-abc123"
instance_type = "t2.micro"
dynamic "security_group" {
for_each = var.security_groups
content {
id = security_group.value
}
}
}
How to Use the Terraform Import Block with Dynamic Blocks
Utilizing Resource Blocks with Terraform Dynamic Block
Instead of having many separate entrance blocks, the example below dynamically generates the repeating ingress blocks using Terraform dynamic blocks.

# variables.tf
variable "settings" {
type = list(object({
description = string
port = number
}))
default = [
{
description = "Allows SSH access"
port = 22
},
{
description = "Allows HTTP traffic"
port = 80
},
{
description = "Allows HTTPS traffic"
port = 443
}
]
}
# main.tf
resource "aws_vpc" "sandbox_vpc" {
cidr_block = "10.0.0.0/16"
instance_tenancy = "default"
tags = {
Name = "sandbox_vpc"
}
}
resource "aws_subnet" "sandbox_subnet" {
vpc_id = aws_vpc.sandbox_vpc.id
cidr_block = "10.0.1.0/24"
tags = {
Name = "sandbox_subnet"
}
}
resource "aws_security_group" "sandbox_sg" {
name = "sandbox_sg"
vpc_id = aws_vpc.sandbox_vpc.id
dynamic "ingress" {
for_each = var.settings
iterator = sandbox_sg_ingress
content {
description = sandbox_sg_ingress.value["description"]
from_port = sandbox_sg_ingress.value["port"]
to_port = sandbox_sg_ingress.value["port"]
protocol = "tcp"
cidr_blocks = [aws_vpc.sandbox_vpc.cidr_block]
}
}
tags = {
Name = "sandbox_sg"
}
}
Using a dynamic block in the configuration eliminates duplicate attributes, enhancing code maintainability. The optional iterator is now the name of the dynamic block, which means subnet.value.name should be used instead of item.value.name in the content block.
Recognizing the block that Terraform transferred
Terraform 1.1+ introduced Terraform moved blocks to refactor infrastructure safely. They notify Terraform of the relocation or renaming of a resource or module.
Syntax:
changed the value of
moved {<br>from = aws_instance.old<br>to = aws_instance.new<br>}
Using Dynamic Blocks:
Keep the block structure constant.
Use it when renaming a resource that has internally specified dynamic blocks.
Example 2: Using Terraform dynamic block in data blocks
In the following example, we use a dynamic block to filter AMIs in a data source based on specific tags. If there are any matches, these AMIs will be returned in a list that can be utilized later in our configuration code.
variable "ami_filters" {
description = "A list of tag filters for finding AMIs"
default = [
{
name = "tag:Purpose"
values = ["WebServer"]
},
{
name = "tag:Environment"
values = ["Prod"]
}
]
}
data "aws_ami" "custom_ami" {
most_recent = true
owners = ["self"]
dynamic "filter" {
for_each = var.ami_filters
content {
name = filter.value.name
values = filter.value.values
}
}
}
Example 3: Setting up an AWS Security Group with Terraform dynamic blocks
There are two ways to define security group rules for AWS with Terraform:
1. Using the security group resource along with a specific security group rule resource.
2. Using just the security group resource (This is the older method and is not advised anymore).
In the first method, the code will look like this:
esource "aws_security_group" "this" {
for_each = var.sg_params
vpc_id = each.value.vpc_id
tags = {
Name = each.key
}
}
resource "aws_security_group_rule" "this" {
for_each = var.sg_rule_params
type = each.value.type
from_port = each.value.from_port
to_port = each.value.to_port
protocol = each.value.protocol
cidr_blocks = each.value.cidr_blocks
security_group_id = aws_security_group.this[each.value.sg_name].id
}
In the second case, using dynamic blocks within the security group would be the best approach.
resource "aws_security_group" "this" {
for_each = var.sg_params
vpc_id = each.value.vpc_id
tags = {
Name = each.key
}
dynamic "ingress" {
for_each = [for rule in each.value.sg_rule_params : 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
}
}
dynamic "egress" {
for_each = [for rule in each.value.sg_rule_params : rule if rule.type == "egress"]
content {
from_port = egress.value.from_port
to_port = egress.value.to_port
protocol = egress.value.protocol
cidr_blocks = egress.value.cidr_blocks
}
}
}
The example uses two dynamic blocks for inbound and outbound traffic, with a single variable for security groups. However, AWS recommends against using aws_security_group for defining rules.
Tips for Troubleshooting Common Issues with a Terraform Dynamic Block:
Here are typical errors and how to resolve them:
- 1. Missing for_each or content Block: Both are required in every dynamic block.
- 2. Wrong Loop Type: for_each must be a map or list; avoid null values.
- 3. Incorrect Iterator Usage: If using a custom iterator, make sure it’s properly referenced in the content.
- 4. Dynamic Block on Unsupported Field: Some fields, like primitive attributes, do not allow dynamic blocks.
Conclusion: Is the Dynamic Block Right for Your Use Case?
Terraform Dynamic Block are undoubtedly the most powerful tools to create scalable, flexible infrastructure-as-code. They reduce readability, allowing you to work more efficiently, especially in Large environments.
While they can still be complex, learning basic troubleshooting tips allows you to tackle them easily. These tips help prevent redundant code by iterating over a list or map to create multiple instances of a nested configuration.
FAQ’s
Q1: What do dynamic blocks do in Terraform?
A Terraform dynamic block creates nested blocks in Terraform configuration files programmatically, based on lists or maps.
Q2: Can I use count within a dynamic block?
No, dynamic blocks only allow for_each. count is not allowed within dynamic blocks.
Q3: How to fix Terraform dynamic block errors?
Verify your code with terraform validate, inspect the data type of for_each, and verify the required attribute of Dynamic Block in Terraform, such as content.
Q4: Can dynamic blocks be used within modules?
Yes, dynamic blocks are commonly utilized within modules for creating conditional or repeatable nested blocks.
Q5: How do dynamic blocks relate to terraform import? When importing existing infrastructure, ensure that dynamic blocks accurately reflect the actual structure of the imported resource to avoid state mismatches.h