Terraform for_each Loops w/ If Statements
Posted by Miguel Lopez on Wed 01 December 2021 in terraform
Technical Stack: Terraform 1.6.0+, AWS
Read: 5 minutes
Introduction
The for_each
meta-argument in Terraform allows you to dynamically create resources or modules based on a map or set of values. Starting with Terraform v0.12.6, this feature became widely available, and by Terraform v1.6.0, additional enhancements made it even more powerful for conditional logic.
This guide demonstrates how to use for_each
with conditional logic to control resource creation dynamically. We'll explore practical examples and best practices for 2025.
Basic for_each Example
A simple for_each
loop looks like this:
resource "aws_s3_bucket" "example" {
for_each = {
group_a = "bucket-1"
group_b = "bucket-2"
}
bucket = each.value
tags = {
Name = each.value
Group = each.key
}
}
Here, Terraform creates two S3 buckets, one for each key-value pair in the map. The each.key
and each.value
expressions allow you to reference the current iteration's key and value.
Building Conditional If Statements
Conditional logic inside for_each
enables you to filter which resources are created. Let's explore an updated example for 2025.
Example: VPC Link for Network Load Balancers
Suppose you want to create a VPC link only for network load balancers. Here's how you can achieve this:
resource "aws_api_gateway_vpc_link" "vpc_link" {
for_each = { for key, value in var.load_balancers : key => value if value.type == "network" }
name = each.key
target_arns = [aws_lb_target_group.example[each.key].arn]
}
Input Example
variable "load_balancers" {
default = {
app_lb = {
type = "application"
}
net_lb = {
type = "network"
}
}
}
Explanation
- The
for_each
expression iterates over theload_balancers
map. - The
if
condition filters only those entries wheretype
equals"network"
. - Terraform creates a VPC link for each matching entry.
Advanced Example: Autoscaling Group with Optional Load Balancers
Imagine you're building a microservice architecture where some services require a load balancer, and others do not. Here's how you can conditionally create load balancers:
Module Example
module "load_balancer" {
for_each = { for key, value in var.services : key => value if lookup(value, "enable_lb", false) }
source = "./modules/load-balancer"
name = each.key
internal = lookup(each.value.lb_config, "internal", true)
lb_type = lookup(each.value.lb_config, "type", "application")
tags = merge(local.common_tags, lookup(each.value, "tags", {}))
}
Input Example
variable "services" {
default = {
api = {
enable_lb = true
lb_config = {
internal = true
type = "application"
}
}
worker = {
enable_lb = false
}
}
}
Explanation
- The
for_each
expression filters services whereenable_lb
istrue
. - The
lookup
function safely retrieves values from nested maps, providing defaults if keys are missing. - Terraform creates a load balancer module only for services with
enable_lb = true
.
Best Practices for 2025
- Use
lookup
for Safe Access: Always uselookup
to avoid errors when accessing optional keys in maps. - Combine
for_each
withdynamic
Blocks: Usedynamic
blocks for conditional nested configurations. - Leverage Local Variables: Simplify complex expressions by breaking them into reusable local variables.
Conclusion
The for_each
meta-argument, combined with conditional logic, is a powerful tool for creating dynamic and reusable Terraform configurations. By leveraging the latest features in Terraform 1.6.0, you can build more flexible and maintainable infrastructure as code.
Start using these patterns in your projects today to streamline resource management and improve scalability!