Refactoring Terraform Safely with moved and removed Blocks
Terraform identifies resources by their address, like aws_s3_bucket.assets. Rename it in code and Terraform plans to destroy the old one and create a new one, which for a database is a disaster. moved and removed blocks tell Terraform what you really meant.
Renaming a resource
resource "aws_s3_bucket" "static_assets" { # was "assets"
bucket = "acme-shop-assets-prod"
}
moved {
from = aws_s3_bucket.assets
to = aws_s3_bucket.static_assets
}
The plan now shows the bucket "has moved", with no destroy or create.
Moving into a module
module "storage" {
source = "./modules/storage"
}
moved {
from = aws_s3_bucket.static_assets
to = module.storage.aws_s3_bucket.assets
}
Switching to count or for_each
moved {
from = aws_instance.web
to = aws_instance.web["primary"]
}
Stop managing without deleting
removed {
from = aws_s3_bucket.legacy_reports
lifecycle {
destroy = false # forget it in state, leave the bucket alone
}
}
Useful when handing a resource over to another team's configuration.
Why blocks beat state commands
- They're code: reviewed, versioned and applied the same way in every environment.
- Module authors can ship
movedblocks so every user of the module upgrades safely. terraform state mvis a one-off manual change, easy to forget in one environment.
Extra safety for critical resources
resource "aws_db_instance" "main" {
# ...
lifecycle {
prevent_destroy = true # plan fails instead of deleting the database
}
}
Was this article helpful?
Comments
No comments yet. Have a question or a tip? Be the first to share it.