Terraform’s for_each construct lets you dynamically create multiple instances of a resource, module, or block using a map or set of strings. This eliminates repetitive code, improves maintainability, and unlocks more powerful patterns in infrastructure as code.
In this guide, we’ll explore how for_each works in Terraform, when to use it over count, and show real-world examples for AWS resources like EC2 instances, S3 buckets, and security groups.
for_each Is PowerfulTerraform supports two ways to loop over resources: count and for_each. While count uses numeric indexes, for_each lets you iterate over:
This allows you to name each resource instance logically and access attributes using meaningful keys instead of index numbers.
resource "aws_s3_bucket" "example" {
for_each = toset(["logs", "archive", "media"])
bucket = "${each.key}-bucket"
acl = "private"
}
This example creates three S3 buckets: logs-bucket, archive-bucket, and media-bucket.
for_each vs count| Aspect | count | for_each |
|---|---|---|
| Indexing | Numeric (count.index) | Named (each.key) |
| Use with maps | Not ideal | Perfect match |
| Stable addressing | Can change with list reordering | More stable (key-based) |
variable "instances" {
default = {
web01 = "t3.micro"
web02 = "t3.small"
}
}
resource "aws_instance" "web" {
for_each = var.instances
ami = "ami-0c55b159cbfafe1f0"
instance_type = each.value
tags = {
Name = each.key
}
}
This will create two EC2 instances with different sizes and logical names as tags.
locals {
buckets = toset(["images", "logs", "backups"])
}
resource "aws_s3_bucket" "bucket" {
for_each = local.buckets
bucket = "${each.key}-project"
acl = "private"
}
each.key in this case is the bucket name string, since we’re looping over a set.
for_eachYou can use for_each to create multiple instances of a module:
module "vpc" {
source = "./modules/vpc"
for_each = {
dev = "10.0.0.0/16"
prod = "172.16.0.0/16"
}
name = each.key
cidr_block = each.value
}
This creates two VPCs with different names and CIDR blocks.
for_each when working with named collections (maps/sets)each.key and each.value clearly in nested structurescount if numeric order mattersTerraform’s for_each construct is one of the most powerful tools in your infrastructure-as-code toolkit. It allows you to write declarative loops without sacrificing readability or control. By leveraging it properly, you can create reusable modules, simplify resource duplication, and build scalable environments across any cloud provider.
Whether you’re launching instances, provisioning S3 buckets, or templating modules — for_each is key to clean, DRY, and maintainable Terraform code.