As part of this article let’s try to understand how can we safely migrate Terraform state from one project to another. But before we start, let us understand when do we need this state migration.

When do we need State migration ?

Terraform state migration can be required mainly for these 2 reasons —

  1. we want to rename the terraform resource without changing the actual resource on the cloud
  2. Due to project architecture change

How can we migrate terraform remote state ?

Terraform state migration can be done in multiple ways —

  1. Delete the existing state using terraform state rm and import the existing resource using terraform state import command in the new place.
  2. Make use of terraform state mv command.

The recommended and preferred way is using terraform state mv command.

How can we make use of terraform state mv command ?

For 1st scenario, where we just want to change the terraform resource name without changing the actual resource on the same project, it’s pretty straight forward. We can just run the following command to do so

terraform state mv "aws_secretsmanager_secret.username" "aws_secretsmanager_secret.github_username"

But for 2nd scenario, the state migration becomes little tricky as it is across two different project/workspace. To be able to safely migrate the state, we need to follow the following steps —

  1. Move the infrastructure code from source project (example: hello_earth) to destination project (example: hello_mars)
  2. Pull existing state for source project (hello_earth). We can use terraform state pull command and store the output into a file ( hello_earth.tfstate ). It’s suggested to create a backup file (hello_earth_backup.tfstate) as well.
  3. Pull existing state for destination project (hello_mars). We can use terraform state pull and store the output into a file ( hello_mars.tfstate ). It’s suggested create a backup file (hello_mars_backup.tfstate) as well.
  4. Figure out the terraform resource ids which you want to migrate by using terraform state list on source project (hello_earth).
  5. Figure out the terraform resource ids in destination project (hello_mars). This can be done by either running terraform plan or can be generated manually. Most of the time it’s <terraform resource type>.<terraform resource name>
  6. Once you are done with the above steps, we can start on actual migration. terraform state mv -state="/Users/john/hello_earth/hello_earth.tfstate"
    -state-out="/Users/john/hello_mars/hello_mars.tfstate" "aws_secretsmanager_secret.username" "aws_secretsmanager_secret.github_username"
  7. Push the newly modified state file for destination project (hello_mars) by using terraform state push "/Users/john/hello_mars/hello_mars.tfstate"
  8. Push the newly modified state file for source project (hello_earth) by using terraform state push "/Users/john/hello_earth/hello_earth.tfstate". We need to do it as we moved terraform state from the source file ( hello_earth.tfstate ) to destination file ( hello_mars.tfstate ) i.e. it’s modified.
  9. Run terraform plan on both the project to verify terraform state move does not any side-effect. Ideally, it should display no changes found. In case, if it displays some changes and changes are not legit, you can always push the backup states and start from the scratch (step 1) without any side effect.
  10. Once you verify the changes, push the modified code for both the projects to the remote (example — Github, BitBucket etc)
Note 1: You may need to run step 6 multiple times depends on how many resource(s) you want to migrate.
Note 2: Until state push happens in step 7 and step 8, there is no side effect or changes in remote state. If you make any mistake, you can always start fresh without any side effect on the remote state.

Terraform state migration process is always little tricky and risky. I hope this article was able to make the process little simpler than previous.

PS: I hope you’ve enjoyed it, and if you’ve found it useful, please feel free to share with others or leave a comment 😃.

Originally posted on medium.com.