Terraform Moved Block: A Code‑First Way to Rename Resources Safely
Migrate Terraform resource addresses safely with the 1.1+ <code>moved</code> block. Learn how it works, see a step‑by‑step example, and avoid common pitfalls for a smooth refactor.
29 Aug 2026, 18:31 UTC

Why Refactor Resource Addresses?
When a team reorganises modules or wants to give a resource a more descriptive name, the simplest approach is to rename the address in the configuration. In Terraform 1.1+ the moved block lets you declare that a resource has moved, so Terraform updates the state instead of destroying and recreating the resource. This keeps the resource alive, avoids downtime, and makes the change part of the normal code‑review workflow.
How the moved Block Works
The block lives inside a module and contains two mandatory fields:
from– the old address (e.g.,module.old_module.aws_instance.web)to– the new address (e.g.,module.new_module.web_server)
During terraform plan, Terraform checks the state for from. If found, it updates the state record to to without touching the underlying resource. The provider never sees a change request, so the physical resource stays intact.
Worked Example
Assume a single‑region AWS setup with an EC2 instance defined in module "app". The team wants to move the instance into a new module called web_server and rename the resource to web_instance.
# modules/app/main.tf
resource "aws_instance" "web" {
ami = var.ami
instance_type = "t3.micro"
}
# modules/web_server/main.tf
# The instance will be moved here
In the root configuration, add the moved block inside the module that currently owns the instance:
module "app" {
source = "./modules/app"
}
module "web_server" {
source = "./modules/web_server"
}
# Declare the move
moved {
from = "module.app.aws_instance.web"
to = "module.web_server.aws_instance.web_instance"
}
Run terraform init first to ensure the provider plugins are available, then:
terraform plan
The output should show a state‑only move with no resource changes:
# Plan: 0 to add, 0 to change, 0 to destroy
# No resource actions
# State-only changes:
# - module.app.aws_instance.web => module.web_server.aws_instance.web_instance
Apply the plan:
terraform apply
After the apply, verify the new address:
terraform state list
# Expected output contains
# module.web_server.aws_instance.web_instance
Common Pitfalls and Limitations
- Static Addresses Only:
fromandtomust be literal strings. Interpolations like"module.${var.name}.aws_instance.web"are not allowed. - Not a Provider‑Side Rename: The provider still sees the same resource. If you need to rename a resource that the provider requires (e.g., an S3 bucket name), you must perform a separate provider‑side rename.
- Removal Before Apply: If you delete the
movedblock before runningterraform apply, Terraform will plan a destroy of the old address and create of the new one, potentially destroying stateful resources. - Version Requirement: The syntax is only accepted by Terraform 1.1+. On 1.0 or earlier, you must use
terraform state mvor other manual state commands.
Verification Checklist
- Run
terraform versionto confirm 1.1 or newer. - Run
terraform planand look for a state‑only move line. - Apply and run
terraform state listto confirm the new address appears. - Optional: Remove the
movedblock, runterraform planagain, and verify a destroy/create is planned. - Restore the block and confirm the plan is clean.
When to Prefer moved Over terraform state mv
In team environments, code review and CI pipelines enforce consistency. By declaring the move in configuration, the change is versioned, auditable, and automatically applied across all workspaces that consume the module. terraform state mv is a manual CLI operation that only affects the local state file and is not automatically propagated to other environments.
Actionable Takeaway
Use the moved block whenever you need to refactor resource addresses within Terraform 1.1+. It keeps the resource alive, integrates cleanly into Git workflows, and reduces the risk of accidental destruction. Just remember the static‑address rule and keep the block in the configuration until the apply completes.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.