Skip to main content
In this lesson we cover one of Terraform’s earliest and simplest iteration mechanisms: the count meta-argument. count is useful for creating multiple copies of a resource from a single block, but it has important implications for identity, indexing, and lifecycle behavior. Read on for concise examples, common pitfalls, and guidance on when to prefer alternatives like for_each. What count does
  • Adding count = N transforms a single resource block into a collection (a list) of N instances rather than a single instance.
  • Inside such a resource block you can reference count.index to get the current instance’s numeric index (starting at 0).
  • Each instance’s identity is positional and based on its numeric index — Terraform tracks resource.name[0], resource.name[1], etc., not by any human-readable name you assign.
Example: two resource groups
This creates:
  • azurerm_resource_group.rg[0] with name rg-0
  • azurerm_resource_group.rg[1] with name rg-1
count.index exists only inside resource blocks that use count and increments from 0 to count - 1.
Use count when instance identity is strictly positional (index-based) and you only need simple duplication with small index-driven differences (for example, suffixes or offsets). For long-lived infrastructure that requires stable identities, prefer for_each.
When count is a poor fit
  • Identity is numeric and positional. If you change count, Terraform will add or remove instances based on indices (it removes the highest indices first), not by any name or metadata you supply.
  • Non-index-based mappings between configuration and logical entities can result in surprising destroys and recreates when indexes shift.
Practical examples
  1. Minimal provider + counted resource groups
Terraform plan (simplified):
  1. Creating a related resource per index
To create one storage account per resource group when both use count, use the same index so instances map 1:1:
This maps sa[0]rg[0], sa[1]rg[1], and so on. Using matching indexes is a straightforward approach when instances should be paired by position.
  1. Binding all instances to a single (first) resource group
If instead you reference a single index explicitly, all of your resources can be tied to that specific instance:
If sa uses count, every sa[i] will be bound to rg[0]. If sa does not use count, this resource is simply created once in rg[0]. Reducing count and the destroy behavior
  • Decreasing count from 3 to 2 on azurerm_resource_group.rg causes Terraform to plan to destroy rg[2] (the highest index), because identities are positional. Example plan when decreasing:
Targeting and dependent resources
  • Removing a middle index (for example rg[1]) is non-trivial. A targeted destroy like:
may still affect other resources. Terraform recalculates dependencies and the collection-level state, so dependent resources can be refreshed, recreated, or destroyed if their references or the collection’s structure change. Important takeaway: targeted operations on counted collections can trigger complex cascades because Terraform maintains collection-level identity and dependency relationships. Removing a middle item often results in recomputations or recreations to keep indices consistent. Why for_each is often better
  • count uses numeric, positional identity.
  • for_each uses stable keys (map keys or set elements) to give each instance a stable identity. With for_each, reordering, partial removals, or additions are less likely to cause unintended resource recreations.
Comparison at a glance
Avoid using count for resources where instance identity must remain stable across reorders, removals, or updates. Prefer for_each when you need deterministic, key-based identities for individual instances.
Summary
  • count is a simple and effective way to duplicate resources when instance identity is purely positional.
  • Instances are identified by index (0..N-1). Changes to count add or remove instances at the end of the list.
  • Removing a middle instance can lead to unintended destroys or recreations because identity is positional.
  • For stable identities and safer updates, use for_each.
Links and references

Watch Video