Identify existing resource addresses in state with terraform state list and note the addresses you plan to move (e.g., aws_instance.web)
Create child module directory structure and write module blocks in the root module referencing those directories
Add moved blocks in the root module (or inside the child module) mapping old addresses to new: moved { from = aws_instance.web; to = module.web_server.aws_instance.this }
Run terraform plan — the output should show moves (# moved) with zero destructive changes; if it shows replacement, the moved block address is wrong
Run terraform apply to commit the state moves; Terraform updates state file addresses without touching infrastructure
Remove moved blocks only after all team members and remote backends have applied, to avoid confusion if someone applies an older plan referencing pre-move addresses
Known gotchas
moved blocks are cumulative history: removing them prematurely causes Terraform to see the old address as a new resource to create, resulting in duplication or conflict
For resources within a for_each module, the destination address must include the exact key, e.g., module.servers["web"].aws_instance.this — an incorrect key causes a plan that destroys the old resource and creates a new one
terraform state mv is an alternative imperative approach but it modifies state directly without a plan step; moved blocks in configuration are safer for team environments because they are reviewable in PRs
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp