Terraform count-to-for_each Migration Prompt
Safely migrate index-based `count` resources to keyed `for_each` so inserting or removing one item stops recreating every resource after it — using `moved` blocks and state moves, with a zero-change plan as proof.
- Target user
- Engineers untangling brittle count-indexed Terraform resources
- Difficulty
- Advanced
- Tools
- Claude, ChatGPT
The prompt
You are a Terraform expert who has rescued teams from the classic "deleted item 2, accidentally rebuilt items 3-10" outage caused by `count` index shifting.
I will provide:
- The resource(s) currently using `count` (the HCL) and the list/expression driving them
- The current `terraform state list` output for those addresses
- Whether items have stable natural keys (names, ids) or only positions
Your job:
1. **Explain the failure mode** — show concretely how removing one element from a `count` list re-indexes everything after it, forcing destroy/recreate, and why `for_each` over a map/set of stable keys fixes it.
2. **Choose the key** — pick a stable, unique key per item (name/id), never the index. Show the transform from the existing list into a `for_each` map (`{ for x in var.items : x.name => x }`). Flag duplicate-key risks.
3. **Rewrite the resource** — convert `count`/`count.index` references to `each.key`/`each.value`. Update every downstream reference (`aws_thing.this[0]` → `aws_thing.this["web"]`), including outputs and `depends_on`.
4. **moved blocks vs state mv** — for each existing instance, generate either a `moved { from = aws_thing.this[0] to = aws_thing.this["web"] }` block (preferred, code-reviewed) or the equivalent `terraform state mv` command if `moved` can't express it.
5. **Map indices to keys** — produce the exact index→key mapping table from the current state so no instance is left orphaned (which would mean a destroy + recreate).
6. **Verification gate** — the migration is correct only if `terraform plan` shows **zero** add/change/destroy. Show how to read the plan and what a non-zero plan means (wrong key mapping).
7. **Rollback** — how to revert the `moved` blocks / state moves if the plan isn't clean.
Output as: (a) before/after HCL, (b) the index→key mapping table, (c) the full set of `moved` blocks (or `state mv` script), (d) the verification + rollback runbook.
Bias toward: `moved` blocks over imperative `state mv`, stable keys over indices, and a zero-change plan as the only acceptable success signal.