DEV Community

Sam Myers
Sam Myers

Posted on


How To Move Individual Resources Across Terraform Backends

Terraform has some fabulous built-in abilities to change where its configuration is stored, but sometimes there's no getting around the need to do state surgery.

The Scenario

In this case, I have a repo with some Terraform configuration. Later, that repo became a module rather than an independent repo.

The straightforward path is to terraform destroy the old resources and terraform apply the new module.

However, there are resources that I want to preserve (S3 buckets, KMS keys...)

Lifecycle Rules

Before we proceed, make absolutely sure that the resources you want to move can't be deleted by accident.

Add the following to any resource to prevent Terraform from deleting it.

lifecycle {
  prevent_destroy = true

If you issue a terraform destroy while those resources are tracked, Terraform will not allow you to proceed.

The Move

The basic plan of attack is to make the source Terraform stop tracking the resource with terraform state rm and get the destination Terraform to start with terraform import.

Open a terminal in both the source and destination Terraform repos.

In this example, we're moving a KMS key.

resource "aws_kms_key" "foo" {
  lifecycle {
    prevent_destroy = true

This is known in the source Terraform as and the destination as

Note that since the repo is a module in the destination that its name is prefixed with module.${MODULE_NAME}.

Get its state from the source

In the source repo

source> terraform state show

id                  = aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
arn                 = arn:aws:kms:us-west-2:REDACTED:key/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
enable_key_rotation = false
is_enabled          = true
key_id              = aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
key_usage           = ENCRYPT_DECRYPT
policy              = ...

Specifically what we are looking for is the first line, the id.

Or for simplicity, terraform state show | head -n1.

We could tell Terraform to stop tracking it at this point, but let's do so after the import to be safe.

Import it into the destination

In your destination repo

destination> terraform import aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee Importing from ID "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"... Import complete!
  Imported aws_kms_key (ID: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee) Refreshing state... (ID: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee)

Import successful!

If this step gives you any trouble, the Terraform docs always give an example of how to import something.

Remove state from the source

Back in your source repo, rm the resource from the state. This will preserve it from any future destroy operations.

source> terraform state rm

1 items removed.
Item removal successful.


That's it. Repeat for all your critical resources.

At the end you get to terraform destroy your old repo and terraform apply your new one.

Top comments (2)

ckousik profile image
Chinmay Kousik


david_j_eddy profile image
David J Eddy

Nice article Sam. Not a topic many people touch on but an important one to know about for sure. Well done examples as well.

An Animated Guide to Node.js Event Loop

Node.js doesn’t stop from running other operations because of Libuv, a C++ library responsible for the event loop and asynchronously handling tasks such as network requests, DNS resolution, file system operations, data encryption, etc.

What happens under the hood when Node.js works on tasks such as database queries? We will explore it by following this piece of code step by step.