moved Blocks: Refactoring Without Destroy/Recreate
Scenario
You renamed a resource from aws_s3_bucket.data to aws_s3_bucket.app_data. Without a moved block, Terraform would destroy the old bucket and create a new one. The moved block tells Terraform "same resource, new name" — no destruction.
Your Objectives
- Create a resource, apply it.
- Rename the resource in code and add a moved block.
- Run plan — observe "moved" instead of "destroy + create".
- Understand moved blocks for module refactoring too.
Additional Context
moved blocks (Terraform 1.1+) are the declarative alternative to terraform state mv. They live in your code, are visible in version control, and work in CI/CD without manual CLI steps.
Step 1: Original config
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = { source = "hashicorp/aws", version = "~> 5.0" }
}
}
provider "aws" { region = "us-east-1" }
data "aws_caller_identity" "current" {}
resource "aws_s3_bucket" "data" {
bucket = "moved-demo-${data.aws_caller_identity.current.account_id}"
tags = { ManagedBy = "terraform" }
}Step 2: Rename + moved block
# Renamed resource: "data" → "app_data"
resource "aws_s3_bucket" "app_data" {
bucket = "moved-demo-${data.aws_caller_identity.current.account_id}"
tags = { ManagedBy = "terraform" }
}
# Tell Terraform: same resource, new name
moved {
from = aws_s3_bucket.data
to = aws_s3_bucket.app_data
}
# For module moves:
# moved {
# from = module.old_name
# to = module.new_name
# }Workflow Commands
terraform init && terraform apply # create the bucket
# Rename in code, add moved block, then:
terraform plan
# aws_s3_bucket.app_data has moved from aws_s3_bucket.data
# Plan: 0 to add, 0 to change, 0 to destroy.
terraform apply # applies the move in state
terraform destroy
✓ Move Plan Output
# aws_s3_bucket.app_data has moved from aws_s3_bucket.data Plan: 0 to add, 0 to change, 0 to destroy.

