Skip to content
DevOps AI ToolKit
Newsletter
All prompts
AI for Terraform Difficulty: Intermediate ClaudeChatGPTCursor

Terraform for_each Set vs Map Keys Prompt

Decide whether a `for_each` should iterate a set of strings or a map of objects so instance keys stay stable, readable, and free of churn when the collection changes.

Target user
Engineers designing or refactoring for_each resources and modules
Difficulty
Intermediate
Tools
Claude, ChatGPT, Cursor

The prompt

You are a Terraform expert who treats `for_each` instance keys as a long-lived contract with the state file, not an implementation detail. You know that the *type* of the collection — a `set(string)` versus a `map(object)` — determines the resource addresses and therefore how much churn a future change causes.

I will provide:
- The resource or module I'm using `for_each` on, and the source collection feeding it
- How that collection is built today (a list, a set, a map, a `toset(...)`, a `{ for ... }` comprehension)
- How often the collection changes and whether reordering or additions are common

Your job:

1. **Classify the current keys** — state the exact instance addresses Terraform will produce (e.g. `aws_iam_user.this["alice"]` vs the value-derived key for a `toset`). Flag any case where the key is derived from a value that can change (an ARN, an index, a computed string), because changing that value silently destroys and recreates the instance.

2. **Recommend set vs map** — use a `set(string)` only when the element value itself is the stable identity. Use a `map(object)` keyed by a human-chosen stable id when the elements carry attributes or when the identity must survive value edits. Show the concrete refactor from one to the other.

3. **Make keys stable** — propose explicit, intention-revealing keys ([STABLE_KEY_SOURCE]) rather than letting Terraform derive them. Rewrite any `{ for x in var.items : x.name => x }` that risks collisions or churn.

4. **Predict the plan** — describe exactly what `terraform plan` will show after the change: pure no-op, in-place updates, or any create/destroy. Any destroy of a stateful instance means the keys moved — author the `moved` blocks to fix it instead of accepting recreation.

5. **Guard the inputs** — add `validation` blocks or `precondition`s that reject duplicate keys, empty identities, or value-derived keys before they reach state.

Output as: (a) the current vs proposed collection type and keys, (b) the rewritten `for_each` and source expression, (c) any `moved` blocks needed to preserve existing instances, (d) the expected plan summary, (e) the validation that prevents future key churn.

Do not propose any change until you've shown the plan it produces; if it recreates a stateful resource, treat that as a defect and supply the `moved` blocks.

Why this prompt works

The single most expensive mistake with for_each is treating instance keys as cosmetic. Terraform stores each instance under its key, so the moment a key changes — because you switched from a toset of values to a map, or because the value you keyed on mutated — Terraform plans a destroy and a create. On a security group or an IAM policy that is a shrug; on an RDS instance or a stateful disk it is an outage. The prompt forces the model to name the exact addresses up front, which is where the risk actually lives, before any HCL gets rewritten.

It also encodes the real decision rule that experienced engineers carry in their heads: a set(string) is right only when the element is the identity, and a map(object) keyed by a deliberately chosen id is right whenever the elements have attributes or whenever you want the identity to survive value edits. By making the model state that rule and apply it to your specific collection, you avoid the common anti-pattern of for_each = toset([for x in var.items : x.name]), which looks tidy and quietly couples your state to a mutable name.

Finally, the guardrails turn a refactor into a reviewable change rather than a leap of faith. Requiring the predicted plan, demanding moved blocks for any unavoidable key shift, and adding input validation means the AI drafts the design but a human verifies it against a real plan before anything touches state. That is the only safe way to refactor for_each on infrastructure you cannot afford to recreate.

Related prompts

Newsletter

Free: the DevOps AI Incident-Triage Cheat Sheet

Subscribe and we’ll send you the one-page cheat sheet — plus weekly AI prompts, automation ideas, and tool reviews for infrastructure engineers. One email a week. No spam, unsubscribe anytime.

  • AI Incident-Triage Cheat Sheet (PDF)
  • Access to 2,104 DevOps AI prompts
  • One practical workflow email per week