# Terraform workflow: refactor with moved blocks, zero recreation
## When
Renaming a resource, moving a resource into or out of a module, or restructuring module boundaries. Anytime an address changes but the real object should not.
## Steps
1. Write the new config (new addresses) AND the moved blocks in the same change:
```
moved {
from = aws_instance.web
to = module.web.aws_instance.main
}
```
2. `terraform plan`. The plan must show moves, not destroy/create. Read every line: any destroy/create pair is a moved block that did not match.
3. Fix mismatches before applying: check `terraform state list` for the real `from` addresses. Typos are the usual cause.
4. `terraform apply`. Verify with `terraform state list` that only the new addresses exist.
5. Keep the moved blocks in config permanently (or at least until every collaborator and CI job has applied past the move). They are cheap and they document history.
## Rules for agents
1. One refactor per change. Mixing a rename with real infrastructure changes makes the plan unreadable and the rollback ambiguous.
2. For bulk renames (count to for_each, module restructuring), generate the moved blocks programmatically and review the generated list. Hand-writing twenty moved blocks invites typos.
3. `terraform state mv` achieves the same result imperatively. Prefer moved blocks in config because they are reviewable and replayable; use state mv only for moves the block syntax cannot express.
4. Never let a refactor plan with destroy/create pairs through review "because it is just a rename". A rename that recreates is a data-loss event for stateful resources.