Terraform moved Block Generator

Turn a list of renames into moved blocks. Write one old and one new address per line, separated by an arrow, a comma or a space.

Paste below, or drop a file anywhere on this panel

Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.

The answer appears here

Paste on the left and press Generate. Nothing leaves this tab.

Examples

Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.

A rename between two types

Terraform rejects it: the stored attributes belong to the old schema

aws_instance.a -> aws_db_instance.a

Two resources swapping names

A cycle has no end state, so it needs a temporary name and two applies

aws_instance.a -> aws_instance.b
aws_instance.b -> aws_instance.a

A module rename with the resources listed too

The module move already covers them, so the extra lines only hide it

module.old -> module.new
module.old.aws_instance.web -> module.new.aws_instance.web

Common mistakes

These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.

  1. Removing the moved blocks in the commit after the rename

    Any environment that has not applied yet still has the old address. Its next apply sees an object with no matching configuration and destroys it.

    Instead:Keep them until every workspace and environment has applied once. Leaving them permanently costs nothing but reading.

  2. Using a moved block to change a resource's type

    The attributes in state belong to the old schema. Terraform rejects the move rather than attempting a conversion.

    Instead:Remove the old resource from state and import the object as the new type.

  3. Writing one moved block per resource when renaming a module

    The module-level move already covers everything inside it, so the extra blocks do nothing and hide the single line that matters in the diff.

    Instead:Write moved from module.old to module.new and delete the rest.

A moved block is instructions for a state that has not caught up

That framing explains every rule below, including the one that catches people out: when it is safe to delete the block again.

Deleting a moved block too early undoes it

The block exists to tell a state with the old address about the new one. Delete it before some workspace or some environment has applied it, and that state still holds the old address, which the configuration no longer contains, so the next apply destroys the object and creates a fresh one. Leave them in for a full pass through every environment.

A rename with no moved block is a destroy and a create

Terraform matches state to configuration by address, and it has no way to tell a rename from a deletion plus an addition. This is why renaming a resource for tidiness is not a cosmetic change.

Moving between resource types is rejected

aws_instance.a to aws_db_instance.a cannot work. The stored attributes belong to the old type's schema and mean nothing to the new one, so Terraform refuses rather than trying and failing halfway. That case needs a state removal and an import, not a move.

A chain is fine and a cycle is not

a to b and b to c resolves in one apply, and that is exactly what accumulates when something is renamed twice over two releases. Two resources swapping names is a cycle, which has no end state and is rejected: it needs a temporary third name and two applies.

Renaming a module is one block, not one per resource

moved from module.old to module.new moves everything inside it. Writing a block per resource as well is harmless and buries the one line that matters, which makes the change harder to review than it needs to be.

moved cannot cross state files

Both addresses are in the same state. Moving an object into another configuration's state is terraform state mv with -state-out, or a removed block plus an import. A moved block pointing at an address in a different state does nothing useful.