How to Master Terraform for_each: 5 Game-Changing Examples

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 🎯

  1. Use Maps Over Sets: While for_each works with both sets and maps, maps give you more flexibility with naming and accessing resources.
  2. 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"]
  }
}
  1. Use Local Variables: Organize complex for_each expressions in local variables for better readability.

Common Pitfalls to Avoid ⚠️

  1. Don’t modify the keys in your for_each map after creation – this will cause Terraform to destroy and recreate resources
  2. Avoid using functions with non-deterministic output in your for_each expressions
  3. Remember that count and for_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”

Leave a Comment