Terraform count vs for_each: Which is Better for Dynamic Resources?
Terraform count vs for_each: Which is Better for Dynamic Resources?
When creating multiple instances of a resource in Terraform, you have two options: count and for_each. Knowing when to use each one is a key concept for writing reliable, maintainable infrastructure code.
Using count
count creates resources using a numeric index starting at 0. It is simple and works well for identical resources.
resource "aws_instance" "server" {
count = 3
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
Name = "server-${count.index}"
}
}
Resources are referenced as aws_instance.server[0], aws_instance.server[1], etc.
The Problem with count
If you remove an item from the middle of the list — say you delete index 1 — Terraform will shift all subsequent indices and recreate every resource after the deleted one. This is dangerous in production environments.
# Before: ["server-a", "server-b", "server-c"]
# After removing "server-b": ["server-a", "server-c"]
# Terraform will DESTROY server-c and RECREATE it as the new index 1!
Using for_each (Recommended)
for_each uses a map or set of strings as unique keys, so each resource is tied to a stable identifier — not a fragile numeric index.
variable "servers" {
default = {
"server-a" = "t2.micro"
"server-b" = "t2.small"
"server-c" = "t2.micro"
}
}
resource "aws_instance" "server" {
for_each = var.servers
ami = "ami-0c55b159cbfafe1f0"
instance_type = each.value
tags = {
Name = each.key
}
}
Resources are referenced as aws_instance.server["server-a"]. Removing “server-b” only destroys that specific resource, leaving others untouched.
for_each with a Set of Strings
resource "aws_iam_user" "devs" {
for_each = toset(["alice", "bob", "charlie"])
name = each.key
}
Quick Comparison
| Feature | count | for_each |
|---|---|---|
| Index type | Numeric (0, 1, 2…) | String key (map/set) |
| Safe to delete middle item | No — causes recreation | Yes — only affects that item |
| Best for | Identical, fixed-count resources | Dynamic, uniquely-keyed resources |
| Reference syntax | resource[0] | resource[“key”] |
Key Takeaway
Prefer for_each over count for any resource list that may change over time. It provides stable, key-based identity and prevents unintended resource replacement when items are added or removed.