Moving a resource

When Terraform projects become large or you want to refactor them, you may need to move a resource from one Terraform project to another. To do this, you cannot simply delete the resource from the Terraform project and add it to the other. If you do, then Terraform will physically delete the resource and recreate it again in the other project. This is often not desirable as it will cause a loss of availability and/or data.

First project example

To solve this problem, we will learn how you can manipulate the Terraform state to move resources between projects:

Press + to interact
provider "aws" {
region = "us-east-2"
}
resource "aws_vpc" "my_vpc" {
cidr_block = "10.1.0.0/16"
tags = {
Name = "vpc"
}
}

Second project example

Next, we’ll create another project. This will be our second Terraform project where we are going to move the resource to:

Press + to interact
provider "aws" {
region = "us-east-2"
}
resource "aws_vpc" "main" {
cidr_block = "10.1.0.0/16"
tags = {
Name = "vpc"
}
}

Both of the projects are pretty similar. They both set up the AWS provider in the same way both define an AWS VPC with the same CIDR range (10.1.0.0/16), and both have a single name tag, vpc. The VPCs do have a different identifier though. In the first project, we use the identifier my_vpc while in the second project the identifier is main.

We have now created our VPC. In this example, we want to move this VPC to the second Terraform project, but we do not want to destroy it. If you remove the block my_vpc from the project and run terraform apply, Terraform will want to destroy the VPC. This is not what we want. To make Terraform stop managing the resource, we have to remove it from Terraform’s state.

Removing the VPC from Terraform’s state

To remove the VPC from the Terraform’s state, we need to use the terraform state rm command. This command needs to be handled with care. To remove the VPC from the state, run

Press + to interact
terraform state rm aws_vpc.my_vpc

You will see Terraform say Removed aws_vpc.my_vpc.

This means that the VPC will not be in Terraform’s state anymore so, as far as Terraform is concerned, it did not create the VPC and is not managing it. Note the VPC still exists in AWS (which is what we wanted). The format of the terraform state rm command is

Press + to interact
terraform state rm <resource_name>.<resource_idenitifier>

Deleting AWS VPC block

Now that the VPC is removed from our first project, go ahead and delete the aws_vpc.my_vpc block from the project and run terraform apply. Terraform will report that there is nothing to do. The reason for this is that Terraform does not know about the VPC anymore. This is the effect the state removal had. We have now successfully removed the VPC from this project but, crucially, it still exists in AWS.

Running the second project

Next, we want to make the second project own the VPC:

  • Run terraform init to initialise Terraform.

  • Open the AWS console in a web browser and go to the VPC section.

  • Find the ID of the VPC that we created using the first Terraform project and copy it to your clipboard.

  • Now run terraform import aws_vpc.main <VPC_ID>.

    This will import the VPC into the state of Terraform.

  • Now run terraform apply and Terraform should report that there is nothing to do.

    This is because Terraform in the second project is now managing the VPC and it matches our HCL code.

    Another interesting aside is that we changed the identifier of the VPC in our HCL code from my_vpc to main.

We have now successfully moved the VPC from one Terraform project to another. Although this was a bit of a trivial example, the technique can be used to break up larger Terraform projects when they become cumbersome to manage.

Another way to move resources

There is another way to move a resource from one project to another, which is to use the terraform state mv command.

Let’s use the terraform state mv command to move the AWS VPC from the second project back to the first project. Before starting this exercise, paste the VPC block back into the first project with the identifier my_vpc.

Run the command:

Press + to interact
terraform state mv -state-out=../state_example_02a/terraform.tfstate aws_vpc.main aws_vpc.my_vpc

What does the command do

This command directs the system to move an item from the Terraform state into the file specified by the flag -state-out. We are pointing that flag to the Terraform state of our first project. The next two arguments are the source resource and the destination resources. Remember, we are using the identifier main in the second project and my_vpc in the first project. Run this command then go into the folder of the first project. If you run terraform apply, you will see Terraform report that there is nothing to do.



This command has slightly different semantics from the remove and then import flow that we first covered. This command removes the resource from the first project’s Terraform state but, rather than importing the resource, puts it directly into the state file.

Terraform state into the file specified by the flag -state-out

An import works a bit differently on the back end. Terraform queries the API of the infrastructure to read the resource and uses that to build the state. On the other hand, the move command copies the state across directly. The advantage of the state mv command is that it works on any resource, even if it does not support an import.

Listing Terraform state

One last thing to cover in this section is listing the Terraform state. In the first project with the VPC, run the command terraform state list. This command lists all of the resources that exist in Terraform’s state file. You should see the following output:

Press + to interact
aws_vpc.my_vpc

The terraform state list command is handy if you want to interrogate Terraform to find out which resources are in its state file.

Get hands-on with 1300+ tech skills courses.