Use Terraform moved blocks and the terraform state mv command together to safely refactor a root module that splits into child modules without destroying resources
Run terraform state list to capture the current addresses of all resources that will move into the new child module structure
Add moved blocks in the root module mapping each old address to the new address under the module path, for example moved { from = aws_s3_bucket.logs to = module.logging.aws_s3_bucket.logs }
Run terraform plan and verify the output shows zero resource replacements and only in-place renames; any replacement indicates a resource attribute changed alongside the move, which must be resolved first
For resources that cannot be expressed as moved blocks (such as those whose provider changed), use terraform state mv commands instead, then add import blocks if the resource needs re-importing under a new provider configuration
After applying the moved configuration, remove the moved blocks in a follow-up commit; moved blocks left in place for more than one release cycle cause confusion but do not cause errors
Tag the pre-move and post-move state in the remote backend by taking a manual state snapshot or using the backend's versioning feature so a rollback path exists if the apply reveals unexpected plan differences
Known gotchas
moved blocks are additive and safe to apply incrementally, but they require that the source address still exists in state at plan time; if the resource was already removed from state, the moved block causes a plan error
When moving a resource into a for_each module, the target address must include the exact key: module.logging["key"].aws_s3_bucket.logs; an incorrect key will create a new resource rather than moving the existing one
Terraform does not validate that the from address in a moved block matches any real resource at write time; a typo silently produces a plan that creates a duplicate resource instead of moving
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