Dynamic blocks vs for_each decision in Terraform - Performance Comparison
We want to understand how the number of operations grows when using dynamic blocks versus for_each in Terraform.
Which approach causes more repeated work as we add more items?
Analyze the time complexity of these two Terraform snippets creating multiple sub-blocks.
resource "aws_security_group" "example" {
name = "example"
dynamic "ingress" {
for_each = var.ingress_rules
content {
from_port = ingress.value.from_port
to_port = ingress.value.to_port
protocol = ingress.value.protocol
cidr_blocks = ingress.value.cidr_blocks
}
}
}
resource "aws_security_group" "example_for_each" {
name = "example-for-each"
ingress = [for rule in var.ingress_rules : {
from_port = rule.from_port
to_port = rule.to_port
protocol = rule.protocol
cidr_blocks = rule.cidr_blocks
}]
}
Both create multiple ingress rules, one using dynamic blocks, the other using for_each in a list.
Look at what repeats as the number of ingress rules grows.
- Primary operation: Creating one ingress rule block per item in the input list.
- How many times: Once for each ingress rule in
var.ingress_rules.
As you add more ingress rules, Terraform creates more blocks or list items.
| Input Size (n) | Approx. Api Calls/Operations |
|---|---|
| 10 | 10 ingress blocks created |
| 100 | 100 ingress blocks created |
| 1000 | 1000 ingress blocks created |
Pattern observation: The number of operations grows directly with the number of ingress rules.
Time Complexity: O(n)
This means the work grows in a straight line as you add more ingress rules.
[X] Wrong: "Using dynamic blocks is slower because it loops inside Terraform, but for_each is faster."
[OK] Correct: Both approaches create one block per item, so the number of operations grows the same way. The difference is mostly in syntax, not performance.
Understanding how repeating resource blocks scale helps you design infrastructure code that stays manageable as it grows.
What if we nested dynamic blocks inside each other? How would the time complexity change?
Practice
Solution
Step 1: Understand nested block repetition
Dynamic blocks are designed to repeat nested blocks inside a single resource.Step 2: Compare with for_each usage
for_each repeats entire resources or top-level blocks, not nested blocks.Final Answer:
Dynamic blocks -> Option AQuick Check:
Nested block repetition = Dynamic blocks [OK]
- Using for_each to repeat nested blocks inside one resource
- Confusing count with dynamic blocks
- Trying to use locals for repeating blocks
setting?Solution
Step 1: Identify correct dynamic block syntax
Dynamic blocks use the syntax: dynamic "block_name" { for_each = ... content { ... } }.Step 2: Check other options for syntax errors
Options A, B, and C misuse for_each, count, or locals incorrectly for nested blocks.Final Answer:
dynamic "setting" { for_each = var.settings; content { key = each.value } } -> Option DQuick Check:
Correct dynamic block syntax = dynamic "setting" { for_each = var.settings; content { key = each.value } } [OK]
- Placing for_each directly inside resource without dynamic
- Using count for nested blocks
- Trying to assign locals directly as blocks
aws_security_group_rule resources created?
resource "aws_security_group_rule" "example" {
for_each = { for idx, port in var.ports : idx => port }
type = "ingress"
from_port = each.value
to_port = each.value
protocol = "tcp"
security_group_id = var.sg_id
}
Assuming var.ports = [80, 443].Solution
Step 1: Understand for_each on resource
for_each creates one resource instance per map or set element. Here, var.ports has 2 elements.Step 2: Count resource instances
Since var.ports has 2 ports, Terraform creates 2 aws_security_group_rule resources, one for each port.Final Answer:
2 resources -> Option BQuick Check:
for_each with 2 items = 2 resources [OK]
- Thinking for_each creates one resource regardless of items
- Confusing dynamic blocks with resource repetition
- Assuming ports combine into one resource
resource "aws_instance" "example" {
for_each = var.instances
ami = "ami-123456"
instance_type = "t2.micro"
dynamic "ebs_block_device" {
for_each = each.value.ebs_volumes
content {
device_name = ebs_block_device.value.device_name
volume_size = ebs_block_device.value.size
}
}
}
Assuming var.instances is a map with nested ebs_volumes lists.Solution
Step 1: Identify the error in dynamic block reference
Inside the content block of a dynamic block, the iterator must be referenced aseach.value, notebs_block_device.value. The iterator variable is alwayseachregardless of the dynamic block name.Step 2: Confirm the fix
Change todevice_name = each.value.device_nameandvolume_size = each.value.size. Other options are incorrect: dynamic blocks work inside resources, for_each works on resources, count is not required.Final Answer:
Incorrect reference to dynamic block variable inside content -> Option CQuick Check:
Dynamic block content uses each.value [OK]
- Using block_name.value inside dynamic block content instead of each.value
- Trying to use for_each on resource incorrectly
- Forgetting to define for_each on dynamic block
variable "users" {
type = map(object({
policies = list(object({
name = string
policy = string
}))
}))
}Solution
Step 1: Manage multiple users
Use for_each on aws_iam_user resource to create one user per map entry.Step 2: Manage multiple policies per user
Since policies are separate resources (aws_iam_user_policy), use for_each on that resource to create one policy per user-policy pair.Step 3: Why not dynamic blocks here?
Dynamic blocks repeat nested blocks inside a resource, but aws_iam_user_policy is a separate resource, so for_each is appropriate.Final Answer:
Use for_each on aws_iam_user for users, and for_each on aws_iam_user_policy for policies -> Option AQuick Check:
Multiple resources = for_each on both [OK]
- Using dynamic blocks to create multiple resources
- Using count instead of for_each for maps
- Trying to nest policies inside user resource with dynamic blocks
Ready to prove it?
Pass the test and this pattern moves unknown
