Course outline

Terraform / Modules and state-aware lifecycle / Lesson 7

Collections and stable instance addresses

Choose repetition keys from durable identity and explain why count indices and for_each keys produce different address behavior.

About 4 min readContent reviewed
On this page

Lesson goals

  • Compare count indices with for_each map or set identities.
  • Recognize known-key requirements and review removals as lifecycle changes.

Repetition is an identity decision

count creates indexed instances such as resource.name[0]. for_each creates instances keyed by a map key or set member. Those addresses become part of state ownership, not merely loop counters. A list suitable for display order may be a poor source of managed identity if inserting an item changes the meaning of existing indices. Stable domain keys make review clearer, but they must remain meaningful and unique. Do not choose generated ids, timestamps, or secret values as convenient keys without considering their evaluation and disclosure requirements.

Declare a keyed service contract

The complete root module below declares two catalogue entries with explicit names and replica metadata. for_each uses the map keys api and worker; each.value supplies the corresponding object. The resource remains built-in teaching data, not a server provisioner. The selected keys must be available when Terraform determines instances. An unknown resource-generated id is therefore unsuitable as a new instance key at this boundary. Outputting the keys is a deliberate identity view, not an application deployment result.

hcl A complete for_each catalogue
terraform {
  required_version = ">= 1.16.0, < 1.17.0"
}

variable "services" {
  type = map(object({ replicas = number }))
  default = {
    api    = { replicas = 2 }
    worker = { replicas = 1 }
  }
}

resource "terraform_data" "service" {
  for_each = var.services
  input = { name = each.key, replicas = each.value.replicas }
}

output "instance_keys" {
  value = sort(keys(terraform_data.service))
}

The declared addresses include terraform_data.service["api"] and ["worker"]. Keys are known from the input map, independent of generated resource ids. The output expression sorts its display; it does not force resource execution order. No instances are applied.

Index changes can redirect existing bindings

When count indices are derived from a mutable list, adding an item at the front shifts which logical item each existing index describes. The resulting arguments may cause updates or replacements depending on the resource schema; reordering does not universally imply deletion, but it deserves review. The Python fixture demonstrates the identity mismatch only. It does not calculate a Terraform plan, resolve a provider schema, or touch state. Never infer operational safety merely because the desired item set is almost unchanged.

python Compare index meaning with stable keys
before = ['api', 'worker']
after = ['metrics', 'api', 'worker']
print(f'count_index_0: {before[0]} -> {after[0]}')
print('stable_keys=' + ','.join(sorted(set(before) & set(after))))
Expected output
count_index_0: api -> metrics
stable_keys=api,worker

Index 0 changes meaning from api to metrics, while api and worker remain common keys. The model is a fixed string comparison. It neither asserts replacement actions nor guarantees that a map-key change can be performed without an explicit state-aware refactor.

Known and nonsensitive identity matters

for_each identities must be determined before the relevant remote actions and cannot rely on sensitive values that would be exposed in addresses. A set of strings removes duplicates and has no user-defined ordering. Converting an ordered list to a set changes its contract, so confirm that uniqueness and order loss are intended. Keep sensitive payloads in values where supported, separate from public instance keys. If an input cannot identify stable instances yet, redesign the interface rather than guessing keys from an expected future result.

A missing key is a proposed ownership transition

Removing a key can remove a declared instance and lead to a destruction proposal under the normal lifecycle. Renaming a key is also an address change, not automatically an in-place label edit. Review moved blocks or another supported refactoring mechanism when identity should continue. Check affected outputs, child modules, policy, and retained data before adopting a new map. A clear input diff is useful, but the actual action-level plan and ownership context remain necessary for any authorized infrastructure change.

Common errors and fixes

Invalid for_each argument.

Why it happens
Instance keys are unknown until a managed operation or have an unsupported shape.
How to fix it
Provide a stable known-key contract and keep generated data in instance values.
Prevent it next time
Review instance identity independently from payload computation.

Reordering a list changes existing object arguments.

Why it happens
Index-based identity was coupled to a changing display sequence.
How to fix it
Use appropriate stable keys or a reviewed address-preserving migration.
Prevent it next time
Test insertion, removal, and reordering before managing repeated objects.

A secret is exposed through an instance key.

Why it happens
A sensitive payload was used as a public configuration identity.
How to fix it
Separate nonsensitive keys from protected values and handle the exposure appropriately.
Prevent it next time
Keep secrets out of resource addresses and diagnostic labels.

Check your understanding

1. Does adding metrics require api to acquire a new key in the map example?

Show worked solution

No. The api key remains api when the map is extended with a separate metrics key. That stability makes the intended identity clearer. Actual resource changes still depend on values, lifecycle, provider behavior, and the reviewed state; stable keys are not a blanket no-change guarantee.

2. Why can renaming worker to jobs require explicit refactoring?

Show worked solution

The key participates in the resource address stored in state. Without a declared identity transition, Terraform can interpret the old key as removed and the new key as a new instance. A moved block can express continuity when the supported refactor and object semantics match the intent.

Key takeaways

  • Stable keys clarify managed identity; lists and sets have different contracts.
  • Review key changes as state-aware lifecycle changes.

Official references