Safeguard
Developer Tools•

Terraform moved blocks: refactor without destroying resources

Renaming a Terraform resource normally plans a destroy and recreate. A moved block updates state instead. Why this matters for databases, keys and buckets.

Safeguard Security Team
3 min read

When you rename a Terraform resource or move it into a module, Terraform sees the old address vanish and a new one appear, and plans to destroy and recreate it. A moved block tells Terraform to rename the object in state first, so nothing is destroyed. Use it for any refactor that touches stateful resources.

The problem

Terraform tracks resources by address, such as aws_db_instance.main. Rename that to aws_db_instance.primary and, to Terraform, the first is gone from the configuration and the second is new. The plan shows one destroy and one create. For a stateless resource that is a nuisance. For a database, a key or a bucket it can be data loss.

What a moved block does

HashiCorp's documentation says the block is used to programmatically change the address of a resource. Terraform checks state for an object at the from address and renames it to the to address before planning. As a result, Terraform does not destroy the resource during that run.

moved {
  from = aws_db_instance.main
  to   = aws_db_instance.primary
}

The page I fetched points to a separate refactoring page for fuller usage, so check that guide for module moves and edge cases.

A safe refactoring routine

  1. Make the rename in code and add the moved block in the same change.
  2. Run a plan and read the summary. You want zero destroys, with the move noted.
  3. If the plan still shows destroy and create, stop. The addresses probably do not match.
  4. Apply, and confirm state shows the new address.
  5. Keep the moved block for a while so other copies of the configuration, such as other environments, also migrate.

Why this is a security topic

Accidental recreation of security-relevant resources causes real incidents:

  • A recreated key store can orphan encrypted data.
  • A recreated bucket loses its policy and public access settings until the next apply restores them.
  • A recreated database loses its data, or comes up with new defaults.
  • A recreated identity role can break trust relationships briefly or permanently.

Reading the plan for any destroy on stateful resources is the review step that prevents most of these. Pair it with lifecycle protections and backups, since protections like prevent_destroy depend on the block staying in the configuration.

Reviewer notes

  • A pull request that renames resources should include moved blocks and a plan showing no destroys.
  • Treat a rename without a moved block as suspicious, especially for stateful types.
  • Never approve a plan you did not read because the diff looked cosmetic.

Safeguard's policies and gates can require checks on pull requests that touch infrastructure files, such as a named approver for destroy actions you configure.

Quick check

What happens if I rename a resource and add no moved block?

Terraform plans to destroy the old address and create the new one, which can mean losing data on stateful resources.

Can I remove a moved block after applying?

Often, once every state that needs migrating has applied it. Keep it while other environments or copies still use the old address.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.