Using Dynamic Blocks
1. Creating Dynamic Blocks
Dynamic blocks in Terraform allow you to generate repetitive configuration blocks dynamically, based on a list or map of values. This is particularly useful when you need to create multiple resources with similar configurations but different values.
| Property | Description | Example |
|---|---|---|
| dynamic | Used to define a dynamic block inside a resource or data source. | dynamic "subnet" { ... } |
| for_each | Iterates over a map or list to create multiple instances of the block. | for_each = var.subnets |
| iterator | Defines the variable name used to reference each item in the loop. | iterator = subnet |
| content | Defines the configuration inside the dynamic block. | content { ... } |
Example: Creating Dynamic Subnets
resource "aws_subnet" "main" {
for_each = var.subnets
vpc_id = aws_vpc.main.id
cidr_block = each.value.cidr
availability_zone = each.value.availability_zone
tags = {
Name = "${each.key}-subnet"
}
}
Example: Using Dynamic Blocks with Maps
resource "aws_security_group_rule" "ingress" {
dynamic "ingress" {
for_each = var.security_rules
content {
from_port = ingress.value.port
to_port = ingress.value.port
protocol = ingress.value.protocol
cidr_blocks = ingress.value.cidr_blocks
}
}
}
2. Iterating with for_each
| Property | Description | Example |
|---|---|---|
| for_each | Creates multiple instances of a resource or module based on a map or set | for_each = { env1 = "prod", env2 = "staging" } |
Example: Using for_each with a resource
resource "aws_instance" "web" {
for_each = {
dev = "t2.micro"
prod = "t3.large"
}
instance_type = each.value
ami = "ami-12345678"
}
Example: Using for_each with a module
module "web_server" {
for_each = {
us_west = { region = "us-west-2", count = 2 }
us_east = { region = "us-east-1", count = 1 }
}
source = "./web_server_module"
region = each.value.region
instance_count = each.value.count
}
for_each creates a separate instance for each key-value pair in the map or set. The each.key and each.value variables are available inside the resource or module block.
for_each map will cause Terraform to destroy and recreate resources. Ensure that keys are stable across runs.
3. Using Iterator Object
| Property | Description | Values | Notes |
|---|---|---|---|
| iterator | Name of the iterator object | string |
Used to reference the current item in a dynamic block |
| for_each | Collection to iterate over | map or set |
Must be a collection of strings, numbers, or objects |
Example: Using iterator object in a dynamic block
resource "aws_instance" "example" {
for_each = {
web = "t2.micro"
db = "t3.small"
}
instance_type = each.value
ami = "ami-12345678"
tags = {
Name = "${each.key}-instance"
}
}
each.key and each.value are accessible within the dynamic block, where each is the default iterator name. You can customize this with the iterator argument.
Example: Custom iterator name
resource "aws_security_group" "example" {
for_each = {
"allow_http" = "80"
"allow_https" = "443"
}
name = each.key
description = "Allow ${each.key}"
dynamic "ingress" {
for_each = each.value
iterator = sg
content {
from_port = sg.value
to_port = sg.value
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
}
4. Accessing Content Block
| Property | Description | Usage |
|---|---|---|
| for_each | Creates a block for each item in a map or list | |
| count | Creates a block for each item in a list or map | |
| dynamic | Allows for conditional creation of blocks | |
Example: Using for_each to create multiple resources
variable "instances" {
type = map(object({
type = string
count = number
}))
default = {
web = {
type = "t2.micro"
count = 2
}
db = {
type = "t2.small"
count = 1
}
}
}
Example: Using dynamic blocks with content
variable "ingress_rules" {
type = list(object({
port = number
cidr = string
}))
default = [
{
port = 80
cidr = "0.0.0.0/0"
},
{
port = 443
cidr = "0.0.0.0/0"
}
]
}
5. Nesting Dynamic Blocks
| Block Type | Description | Usage |
|---|---|---|
| dynamic | Allows for dynamic generation of nested blocks within a resource or module | dynamic "block_name" { for_each = list } |
Example: Nesting Dynamic Blocks
resource "aws_security_group" "example" {
name = "example-sg"
dynamic "ingress" {
for_each = var.ingress_rules
content {
from_port = ingress.value.port
to_port = ingress.value.port
protocol = ingress.value.protocol
cidr_blocks = ingress.value.cidr_blocks
}
}
dynamic "egress" {
for_each = var.egress_rules
content {
from_port = egress.value.port
to_port = egress.value.port
protocol = egress.value.protocol
cidr_blocks = egress.value.cidr_blocks
}
}
}
for_each attribute in nested dynamic blocks must be a map or list of objects. The content block defines the structure of each generated block.
Nesting Dynamic Blocks - Key Points
- Dynamic blocks can be nested inside other dynamic blocks.
- Each nested block must define its own
for_eachandcontent. - Useful for generating complex configurations with variable structures.
6. Using Conditional Dynamic Blocks
| Property | Description | Example |
|---|---|---|
| count | Controls how many instances of a block to create. Can be used with dynamic blocks. | count = var.instance_count |
| for_each | Creates a block for each item in a map or set. Works well with dynamic blocks. | for_each = var.tags |
| condition | Used inside a dynamic block to conditionally include or exclude the block. | condition = var.enable_logging |
Example: Conditional Dynamic Block with condition
resource "aws_cloudwatch_log_group" "example" {
count = var.enable_logging ? 1 : 0
name = "/aws/lambda/${var.function_name}"
}
Example: Using for_each with Dynamic Blocks
resource "aws_security_group_rule" "ingress" {
for_each = var.ingress_rules
type = "ingress"
from_port = each.value.port
to_port = each.value.port
protocol = each.value.protocol
cidr_blocks = each.value.cidr_blocks
}
7. Combining Dynamic and Static Blocks
Dynamic blocks can be combined with static blocks within the same resource or module to provide more flexible and maintainable configurations.
| Block Type | Description | Usage Example |
|---|---|---|
| dynamic | Allows for the creation of repeatable blocks with dynamic content based on a list or map | |
| static | Fixed, predefined block that does not change during configuration evaluation | |
Example: Combining Dynamic and Static Blocks
resource "aws_security_group" "example" {
name = "example"
description = "Example security group with dynamic and static blocks"
# Static block
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
# Dynamic block
dynamic "ingress" {
for_each = var.ports
content {
from_port = ingress.value.internal
to_port = ingress.value.external
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
}
8. Using Dynamic Blocks for Complex Objects
Dynamic blocks in Terraform allow you to generate nested blocks dynamically, which is particularly useful for complex objects like aws_security_group_rule or google_compute_firewall_rule. This feature is especially powerful when you need to create multiple similar blocks with varying configurations.
| Property | Description | Example Value |
|---|---|---|
| dynamic | Used to define a dynamic block inside a resource or data source | dynamic "rule" { ... } |
| for_each | Iterates over a map or list to generate multiple blocks | for_each = var.rules |
| iterator | Name of the iterator variable used inside the dynamic block | iterator = rule |
| content | Defines the content of each generated block | content { ... } |
Example: Using Dynamic Blocks for Security Group Rules
resource "aws_security_group" "example" {
name = "example-sg"
description = "Example security group"
dynamic "ingress" {
for_each = var.ingress_rules
content {
from_port = ingress.value.port
to_port = ingress.value.port
protocol = ingress.value.protocol
cidr_blocks = ingress.value.cidr_blocks
}
}
dynamic "egress" {
for_each = var.egress_rules
content {
from_port = egress.value.port
to_port = egress.value.port
protocol = egress.value.protocol
cidr_blocks = egress.value.cidr_blocks
}
}
}
Example: Complex Nested Object with Multiple Attributes
resource "google_compute_firewall" "example" {
name = "example-firewall"
network = google_compute_network.example.self_link
dynamic "rule" {
for_each = var.firewall_rules
content {
direction = rule.value.direction
priority = rule.value.priority
dynamic "source_ranges" {
for_each = rule.value.source_ranges
content {
value = source_ranges.value
}
}
dynamic "target_tags" {
for_each = rule.value.target_tags
content {
value = target_tags.value
}
}
dynamic "allowed" {
for_each = rule.value.allowed
content {
protocol = allowed.value.protocol
ports = allowed.value.ports
}
}
}
}
}
for_each with dynamic blocks, ensure that the input map or list contains valid keys and values. Invalid keys or missing required attributes will cause Terraform to fail during validation.
terraform plan.
9. Setting Custom Iterator Names
When using dynamic blocks in Terraform, you can customize the iterator name to control how the loop variable is referenced within the block. By default, Terraform uses each as the iterator name, but you can override this using the iterator argument.
| Argument | Description | Default Value |
|---|---|---|
| iterator | Specifies the name of the iterator variable used in the dynamic block. | each |
Example: Custom Iterator Name
resource "aws_instance" "web" {
count = length(var.instances)
dynamic "tags" {
for_each = var.instances
iterator = "instance"
content {
Name = instance.value.name
Environment = instance.value.environment
}
}
}
iterator argument allows you to use a custom variable name inside the dynamic block, which can improve readability when working with complex data structures.
10. Using Dynamic Labels
| Property | Description | Example |
|---|---|---|
| dynamic | Used to create dynamic blocks in Terraform configurations | |
Example: Defining Dynamic Labels
resource "aws_instance" "example" {
ami = "ami-12345678"
instance_type = "t2.micro"
dynamic "tags" {
for_each = var.tags
content {
key = tags.key
value = tags.value
}
}
}
dynamic block allows you to create multiple blocks of the same type with different values, useful for labels or tags that vary by environment or deployment.