5.6. Moved Block
Preparation
Create a new directory for this exercise:
mkdir -p $LAB_ROOT/advanced/moved
cd $LAB_ROOT/advanced/moved
Optional: Create empty files:
touch {main,versions}.tf
Step 5.6.1: Initial setup
Create a new file named main.tf with an intentionally short resource name that we will later
want to rename:
resource "local_file" "tmp" {
filename = "output.txt"
content = "hello from terraform"
}
Create a new file named versions.tf and add the following content:
terraform {
required_version = ">= 1.12.2"
required_providers {
local = {
source = "hashicorp/local"
version = "= 2.5.2"
}
}
}
Apply to create the resource in state:
terraform init
terraform apply
Step 5.6.2: Rename the resource – the wrong way
Rename local_file.tmp to local_file.greeting in main.tf without a moved block:
resource "local_file" "greeting" {
filename = "output.txt"
content = "hello from terraform"
}
Run terraform plan:
terraform plan
Plan: 1 to add, 0 to change, 1 to destroy.
Terraform treats this as a delete + create because the old address no longer exists. In a real environment this would delete and re-provision a running resource—potentially causing downtime. Do not apply. Restore the original name before continuing.
Step 5.6.3: Rename safely with a moved block
Update main.tf to the new name and add a moved block that tells Terraform the old and new
addresses:
resource "local_file" "greeting" {
filename = "output.txt"
content = "hello from terraform"
}
moved {
from = local_file.tmp
to = local_file.greeting
}
Run terraform plan:
terraform plan
Terraform will perform the following actions:
# local_file.tmp has moved to local_file.greeting
resource "local_file" "greeting" {
...
}
Plan: 0 to add, 0 to change, 0 to destroy.
No destroy/create cycle—Terraform simply updates the state record. Apply to confirm:
terraform apply
After the apply succeeds you can remove the moved block (or keep it as documentation of the
rename history).
Explanation
The moved block (introduced in Terraform 1.1) records a renaming or refactoring operation
directly in the code. Its key properties:
- Zero-downtime renames – no destroy/create occurs; only the state entry is relocated.
- Module moves – can relocate resources across module boundaries:
moved { from = local_file.greeting to = module.files.local_file.greeting } - Idempotent – if the
fromaddress is not in state (e.g. already moved), the block is a no-op. - Reviewable – the rename is explicit in code, visible in pull requests.
Note
Themoved block only relocates state records. It does not change the physical infrastructure.
Always run terraform plan after adding a moved block to confirm the plan shows zero
destroy/create operations before applying.Step 5.6.4: Rename within a for_each resource
The moved block also supports renaming keys within a for_each resource. For example, to rename
the key "dev" to "development" without re-creating the resource:
moved {
from = local_file.configs["dev"]
to = local_file.configs["development"]
}
This pattern is useful when cleaning up naming conventions in an existing for_each map.