Free — no signup required

Loops: count vs. for_each

2 min read

The Index Problem

Creating multiple similar resources is one of the most common Terraform tasks. Terraform provides two mechanisms for this: count and for_each. They look similar but have fundamentally different behavior, and choosing the wrong one causes destructive, unintended infrastructure changes.

Option A: count — Simple but Fragile

count creates N copies of a resource, addressed by numeric index:

variable "users" {
  default = ["alice", "bob", "charlie"]
}

resource "aws_iam_user" "u" {
  count = length(var.users)
  name  = var.users[count.index]
}

Terraform tracks these as aws_iam_user.u[0], aws_iam_user.u[1], aws_iam_user.u[2].

The trap: Remove "alice" from the beginning of the list. The list becomes ["bob", "charlie"]. Now:

  • Index 0 = "bob" (was "alice") → Terraform destroys alice, creates bob
  • Index 1 = "charlie" (was "bob") → Terraform destroys bob, creates charlie
  • Index 2 no longer exists → Terraform destroys charlie

Three destructive operations to remove one user. If these were database users with attached permissions, you just caused an outage.

Option B: for_each — Stable and Correct

for_each creates resources keyed by a string identifier, not a numeric index:

resource "aws_iam_user" "u" {
  for_each = toset(var.users)
  name     = each.key
}

Terraform tracks these as aws_iam_user.u["alice"], aws_iam_user.u["bob"], aws_iam_user.u["charlie"].

Remove "alice" from the list. Terraform sees:

  • aws_iam_user.u["alice"] no longer in config → destroy only Alice
  • aws_iam_user.u["bob"] unchanged → no action
  • aws_iam_user.u["charlie"] unchanged → no action

One targeted destroy. Bob and Charlie are untouched.

for_each with maps is even more powerful — the key doesn't have to be a bare identifier from a list, it can index into a map of structured per-resource configuration, so each instance can carry its own settings (region, feature flags, sizing) while still being addressed by a stable name rather than a position.

Rule of thumb: Use count only when the number of resources is truly numeric and order-independent (e.g., count = var.replica_count for identical read replicas). Use for_each whenever resources have distinct identities.

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free