TL;DR 📌
Tired of copying and pasting similar Terraform resource blocks? terraform for_each
is your new best friend! This powerful meta-argument helps you write cleaner, more maintainable infrastructure code by creating multiple resource instances from a single block. Let’s dive deep into how it works and when to use it.
What is for_each? 🤔
Think of for_each
as your infrastructure code’s copy machine. Instead of writing multiple similar resource blocks, you write one block and tell Terraform to create multiple instances with different parameters. It’s like having a template that you can use to create multiple resources with different configurations.
Why Should You Care? 💡
- Reduces code duplication (DRY principle)
- Makes maintenance easier
- Decreases the chance of errors
- Simplifies resource management
- Makes your code more professional
The Basics: How to Use for_each 🔧
Let’s start with a simple example. Imagine you need to create multiple S3 buckets for different departments:
variable "buckets" {
type = map(object({
environment = string
access_logs = bool
}))
default = {
"marketing" = { environment = "prod", access_logs = true }
"sales" = { environment = "prod", access_logs = true }
"dev" = { environment = "dev", access_logs = false }
}
}
resource "aws_s3_bucket" "department_buckets" {
for_each = var.buckets
bucket = "company-${each.key}-${each.value.environment}"
tags = {
Department = each.key
Environment = each.value.environment
HasLogs = each.value.access_logs
}
}
Advanced Usage: Real-World Scenarios 🌟
1. Managing Multiple IAM Users
locals {
developers = {
"john" = ["project-a", "project-b"]
"jane" = ["project-a", "project-c"]
"bob" = ["project-b"]
}
}
resource "aws_iam_user" "team" {
for_each = local.developers
name = each.key
}
resource "aws_iam_user_policy_attachment" "project_access" {
for_each = {
for pair in flatten([
for user, projects in local.developers : [
for project in projects : {
user = user
project = project
}
]
]) : "${pair.user}-${pair.project}" => pair
}
user = aws_iam_user.team[each.value.user].name
policy_arn = "arn:aws:iam::policy/${each.value.project}-access"
}
2. Creating Multiple VPC Subnets
locals {
subnets = {
"web-1a" = { cidr = "10.0.1.0/24", az = "us-east-1a" }
"web-1b" = { cidr = "10.0.2.0/24", az = "us-east-1b" }
"database-1a" = { cidr = "10.0.3.0/24", az = "us-east-1a" }
"database-1b" = { cidr = "10.0.4.0/24", az = "us-east-1b" }
}
}
resource "aws_subnet" "app_subnets" {
for_each = local.subnets
vpc_id = aws_vpc.main.id
cidr_block = each.value.cidr
availability_zone = each.value.az
tags = {
Name = each.key
Type = split("-", each.key)[0]
}
}
Pro Tips 🎯
- Use Maps Over Sets: While
for_each
works with both sets and maps, maps give you more flexibility with naming and accessing resources. - Combine with Dynamic Blocks: You can use
for_each
inside dynamic blocks for even more powerful resource configuration:
dynamic "ingress" {
for_each = var.service_ports
content {
from_port = ingress.value
to_port = ingress.value
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
- Use Local Variables: Organize complex
for_each
expressions in local variables for better readability.
Common Pitfalls to Avoid ⚠️
- Don’t modify the keys in your
for_each
map after creation – this will cause Terraform to destroy and recreate resources - Avoid using functions with non-deterministic output in your
for_each
expressions - Remember that
count
andfor_each
can’t be used together in the same resource block
FAQ Section 🤔
Q: Can I use for_each with module blocks?
A: Yes! Since Terraform 0.13, you can use for_each
with modules just like with resources.
Q: What’s the difference between count and for_each?
A: While both create multiple instances, for_each
is generally preferred because it uses map keys instead of numeric indices, making it more maintainable and less prone to errors when removing items from the middle of a list.
Q: Can I use for_each with data sources?
A: Yes, for_each
works with data sources just like it does with resources.
Q: What happens if I change a key in my for_each map?
A: Changing a key will cause Terraform to destroy the resource associated with the old key and create a new one with the new key. Be very careful with key modifications!
Conclusion 🎉
Terraform for_each
is a powerful feature that can significantly improve your Terraform configurations. By using it effectively, you can write more maintainable, scalable infrastructure code. Remember to start simple and gradually incorporate more complex patterns as you become comfortable with the basics.
Have questions about using for_each in your infrastructure? Drop a comment below or reach out on Twitter! Don’t forget to subscribe to our newsletter for more infrastructure-as-code tips and tricks.
Next: 7 AWS Data Pipeline Secrets That Will Double Your Efficiency 🚀
1 thought on “How to Master Terraform for_each: 5 Game-Changing Examples”