A Better Way to Rename Resources
Terraform 1.1 introduced the moved block as a declarative alternative to terraform state mv. Instead of running a CLI command that modifies state directly, you express the rename in your code, and Terraform handles the state update automatically during the next plan and apply.
This is safer and more auditable — the rename is recorded in version control, visible in code review, and applied consistently by every team member and CI/CD pipeline without requiring manual CLI intervention.
How It Works
When you rename a resource in your code, adding a moved block right alongside it — naming the old address as from and the new one as to — tells Terraform: "this address moved, update state, don't destroy." The resulting plan shows the resource as "moved" with zero attribute changes, and critically: 0 to add, 0 to change, 0 to destroy. No destroy. No create. Just a state rename.
moved Blocks for Module Refactoring
moved blocks are especially powerful when moving resources into or out of modules — the same from/to pattern works just as well when the destination address is a resource nested inside a child module, not just a renamed resource at the same level.
Lifecycle of a moved Block
Once the moved block has been applied by all environments (dev, staging, prod), you can delete it from the code. It's a one-time migration instruction, not a permanent configuration. Some teams keep moved blocks for one or two release cycles to ensure all environments have been updated before removing them.
Key Point: moved blocks are composable — you can chain them. If a resource was renamed twice across two releases, you can have two moved blocks: one from the original name to the intermediate name, and one from the intermediate name to the final name. Terraform resolves the chain automatically. However, circular moves (A → B → A) are detected and rejected as an error.