How do you move existing resources into a Terraform module without recreating them?
Quick Answer
Use moved blocks in Terraform 1.1+ to declare that a resource has moved from its old address to a new address inside a module. Terraform updates the state file without destroying or recreating the resource. For older versions, use terraform state mv to manually remap resource addresses.
Detailed Answer
Think of reorganizing books on a shelf. You are not buying new books or throwing old ones away — you are just moving them from one shelf to another and updating the library catalog. The physical books (cloud resources) stay exactly the same; only the catalog entry (state file address) changes. If you do not update the catalog, the librarian thinks the book is missing from the old shelf and orders a new one while discarding the one on the new shelf.
When you refactor Terraform code to extract resources into modules, the resource address changes. A resource that was aws_security_group.payments_sg becomes module.networking.aws_security_group.payments_sg. Without telling Terraform about this move, it sees the old address as 'resource to destroy' and the new address as 'resource to create' — which means production downtime while it deletes and recreates your security group.
The moved block, introduced in Terraform 1.1, solves this declaratively. You add a moved block to your configuration that tells Terraform: 'the resource that used to be at address X is now at address Y.' When you run terraform plan, Terraform sees the move instruction, updates the state file to reflect the new address, and shows no create or destroy actions. The moved block can stay in your code permanently as documentation, or be removed after all teams have applied the change.
At production scale, refactoring into modules is a multi-step process. First, write the module and add moved blocks for every resource being relocated. Second, run terraform plan to verify zero creates and zero destroys — only state moves. Third, apply to update the state. Fourth, optionally remove the moved blocks after all environments have applied. For complex refactors involving dozens of resources, use terraform state mv as a batch operation with a script that generates all the state mv commands.
The non-obvious gotcha is that moved blocks only work within the same state file. If you are splitting resources into a completely separate state file (different backend), you need terraform state mv -state-out to export resources, then terraform import in the new state. This two-step process has a window where the resource exists in neither state, so plan carefully and do it during a maintenance window.