count and for_each meta-arguments. Both create multiple instances of a resource from a collection, but they record resource identity differently in the Terraform state. Choosing the wrong one can cause unexpected resource deletion and recreation in production—so understanding the differences is important.
Quick overview
countcreates instances indexed by number:resource.example[0],resource.example[1].for_eachcreates instances keyed by an element from the collection:resource.example["key"].
- count: Terraform tracks instances by numeric index. If the order of the input list changes, instances shift indices and Terraform may plan to destroy and recreate resources to match new indices.
- for_each: Terraform tracks instances by key derived from the collection (element value for sets or keys for maps). As long as keys stay the same, resources remain stable even if the collection is reordered.
count (index-based):
for_each (key-based):
-
With
count:- Inside the resource:
count.index - Outside the resource:
aws_resource.example_count[0].id,aws_resource.example_count[1].id
- Inside the resource:
-
With
for_each:- Inside the resource:
each.key(oreach.valuewhen iterating maps) - Outside the resource:
aws_resource.example_each["rg-dev"].id,aws_resource.example_each["rg-prod"].id
- Inside the resource:
Behavior when inputs change
- count: Because instances are index-driven, inserting, removing, or reordering items in a list can change indices. Terraform will view shifted indices as different resources and may destroy/create instances to reconcile state.
- for_each: Because instances are key-driven, reordering a collection does not affect existing resources. Adding or removing keys only adds or removes the specific instances affected.
- With
count, Terraform creates:resource[0]-> “a”,resource[1]-> “b”,resource[2]-> “c”. If the list becomes["b","a","c"], indices change and Terraform may recreate resources. - With
for_each(e.g.,for_each = toset(var.items)), Terraform creates keys"a","b","c". Reordering the list does not change keys or result in recreation.
for_each. Example:
toset()deduplicates and loses order. If duplicates in your list matter, do not convert to a set. Use a map keyed by a stable identifier or create explicit keys withzipmap.- If you must use
countwith a list, keep the list ordering stable (for example, sort it explicitly) to avoid index shifts. for_eachrequires keys to be unique. For lists usetoset()only when duplicates aren’t significant; otherwise, map elements to unique keys.- When converting a list to a map for stable keys, you can use
zipmap()to build explicit keys.
- Default to
for_eachfor long-lived, production resources where stable identity matters. - Use
countfor simple numeric repetition (like creating N identical test resources) or when you intentionally want index semantics. - Use maps with
for_eachfor predictable keys and to attach metadata per item. - Be deliberate when changing the input collection for an existing resource block; plan and review
terraform planto avoid accidental destruction.
Prefer
for_each for stable, long-lived resources and count for simple numeric repetition. Remember that toset() removes duplicates and discards order—use maps or zipmap() to create deterministic keys when you need stable identities and per-item metadata.count and for_each is complete.