Skip to main content
This article compares Terraform’s 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
  • count creates instances indexed by number: resource.example[0], resource.example[1].
  • for_each creates instances keyed by an element from the collection: resource.example["key"].
Minimal usage examples
How Terraform tracks identity
  • 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.
Concrete resource examples Using count (index-based):
Using for_each (key-based):
Referencing created resources
  • With count:
    • Inside the resource: count.index
    • Outside the resource: aws_resource.example_count[0].id, aws_resource.example_count[1].id
  • With for_each:
    • Inside the resource: each.key (or each.value when iterating maps)
    • Outside the resource: aws_resource.example_each["rg-dev"].id, aws_resource.example_each["rg-prod"].id
Comparison table 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.
Example scenario Initial variable:
  • 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.
Stable keys and metadata When you need stable identifiers plus per-item attributes, prefer a map for for_each. Example:
Important nuances and gotchas
  • 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 with zipmap.
  • If you must use count with a list, keep the list ordering stable (for example, sort it explicitly) to avoid index shifts.
  • for_each requires keys to be unique. For lists use toset() 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.
Best practices
  • Default to for_each for long-lived, production resources where stable identity matters.
  • Use count for simple numeric repetition (like creating N identical test resources) or when you intentionally want index semantics.
  • Use maps with for_each for predictable keys and to attach metadata per item.
  • Be deliberate when changing the input collection for an existing resource block; plan and review terraform plan to avoid accidental destruction.
Reference links
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.
With this, the comparison between count and for_each is complete.

Watch Video