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_eachexpression iterates over theload_balancersmap. - The
ifcondition filters only those entries wheretypeequals"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_eachexpression filters services whereenable_lbistrue. - The
lookupfunction 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
lookupfor Safe Access: Always uselookupto avoid errors when accessing optional keys in maps. - Combine
for_eachwithdynamicBlocks: Usedynamicblocks 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!