Skip to main content

Command: state mv

The main function of OpenTofu state is to track the bindings between resource instance addresses in your configuration and the remote objects they represent. Normally OpenTofu automatically updates the state in response to actions taken when applying a plan, such as removing a binding for an remote object that has now been deleted.

You can use tofu state mv in the less common situation where you wish to retain an existing remote object but track it as a different resource instance address in OpenTofu, such as if you have renamed a resource block or you have moved it into a different module in your configuration.


Usage: tofu state mv [options] SOURCE DESTINATION

OpenTofu will look in the current state for a resource instance, resource, or module that matches the given address, and if successful it will move the remote objects currently associated with the source to be tracked instead by the destination.

Both the source and destination addresses must use resource address syntax, and they must both refer to the same kind of object: you can only move a resource instance to another resource instance, a whole module instance to another whole module instance, etc. Furthermore, if you are moving a resource or a resource instance then you can only move it to a new address with the same resource type.

The most common uses for tofu state mv are when you have renamed a resource block in your configuration or you've moved a resource block into a child module, in both cases with the intention of retaining the existing object but tracking it under a new name. By default OpenTofu will understand moving or renaming a resource configuration as a request to delete the old object and create a new object at the new address, and so tofu state mv allows you to override that interpretation by pre-emptively attaching the existing object to the new address in OpenTofu.

This command also accepts the following options:

  • -dry-run - Report all of the resource instances that match the given address without actually "forgetting" any of them.

  • -lock=false - Don't hold a state lock during the operation. This is dangerous if others might concurrently run commands against the same workspace.

  • -lock-timeout=DURATION - Unless locking is disabled with -lock=false, instructs OpenTofu to retry acquiring a lock for a period of time before returning an error. The duration syntax is a number followed by a time unit letter, such as "3s" for three seconds.

For configurations using the cloud backend or the remote backend only, tofu state mv also accepts the option -ignore-remote-version.

The legacy options -backup and -backup-out operate on a local state file only. Configurations using the remote backend must specify a local state file with the -state option in order to use the -backup and -backup-out options.

For configurations using the local state mv only, tofu state mv also accepts the legacy options -state, -state-out, -backup, and -backup-out.

Example: Rename a Resource

Renaming a resource means making a configuration change like the following:

Code Block
-resource "packet_device" "worker" {
+resource "packet_device" "helper" {
# ...

To tell OpenTofu that it should treat the new "helper" resource as a rename of the old "worker" resource, you can pair the above configuration change with the following command:

Code Block
tofu state mv packet_device.worker packet_device.helper

Example: Move a Resource Into a Module

If you originally wrote a resource in your root module but now wish to refactor it into a child module, you can move the resource block into the child module configuration, removing the original in the root module, and then run the following command to tell OpenTofu to treat it as a move:

Code Block
tofu state mv packet_device.worker module.worker.packet_device.worker

In the above example the new resource has the same name but a different module address. You could also change the resource name at the same time, if the new module organization suggests a different naming scheme:

Code Block
tofu state mv packet_device.worker module.worker.packet_device.main

Example: Move a Module Into a Module

You can also refactor an entire module into a child module. In the configuration, move the module block representing the module into a different module and then pair that change with a command like the following:

Code Block
tofu state mv

Example: Move a Particular Instance of a Resource using count

A resource defined with the count meta-argument has multiple instances that are each identified by an integer. You can select a particular instance by including an explicit index in your given address:

Code Block
$ tofu state mv 'packet_device.worker[0]' 'packet_device.helper[0]'

A resource that doesn't use count or for_each has only a single resource instance whose address is the same as the resource itself, and so you can move from an address not containing an index to an address containing an index, or the opposite, as long as the address type you use matches whether and how each resource is configured:

Code Block
$ tofu state mv 'packet_device.main' 'packet_device.all[0]'

Brackets ([, ]) have a special meaning in some shells, so you may need to quote or escape the address in order to pass it literally to OpenTofu. The above examples show the typical quoting syntax for Unix-style shells.

Example: Move a Resource configured with for_each

A resource defined with the for_each meta-argument has multiple instances that are each identified by an string. You can select a particular instance by including an explicit key in your given address.

However, the syntax for strings includes quotes and the quote symbol often has special meaning in command shells, so you'll need to use the appropriate quoting and/or escaping syntax for the shell you are using. For example:

Unix-style shells, such as on Linux or macOS:

Code Block
tofu state mv 'packet_device.worker["example123"]' 'packet_device.helper["example456"]'

Windows Command Prompt (cmd.exe):

Code Block
tofu state mv packet_device.worker[\"example123\"] packet_device.helper[\"example456\"]


Code Block
tofu state mv 'packet_device.worker[\"example123\"]' 'packet_device.helper[\"example456\"]'

Aside from the use of strings instead of integers for instance keys, the treatment of for_each resources is similar to count resources and so the same combinations of addresses with and without index components is valid as described in the previous section.