5.5. Import

Preparation

Create a new directory for this exercise:

mkdir -p $LAB_ROOT/advanced/import
cd $LAB_ROOT/advanced/import

Optional: Create empty files:

touch {main,outputs,versions}.tf

Step 5.5.1: Define the configuration

A common real-world scenario for terraform import is when a resource was created by a previous Terraform run but the state file was accidentally deleted or corrupted — for example after a botched workspace migration. Without the state entry Terraform treats the resource as non-existent and would try to create a new one, producing a completely different value and breaking any infrastructure that depended on the original.

In this lab you will use a random_string resource that generates a unique suffix — a very common pattern for globally unique resource names. You will apply it, simulate state loss, and then import the resource back into state.

Create a new file named main.tf with the following content:

resource "random_string" "suffix" {
  length  = 8
}

Create a new file named outputs.tf with the following content:

output "suffix" {
  value = random_string.suffix.result
}

Create a new file named versions.tf with the following content:

terraform {
  required_version = ">= 1.12.2"

  required_providers {
    random = {
      source  = "hashicorp/random"
      version = "= 3.7.1"
    }
  }
}

Run terraform init and terraform apply to create the resource:

terraform init
terraform apply

Terraform creates the random string and stores it in state. Save the generated value to a shell variable — you will need it in the import steps:

SUFFIX=$(terraform output -raw suffix)
echo "Generated suffix: $SUFFIX"
Generated suffix: k7m2px4n

Step 5.5.2: Simulate state loss

Remove the resource from the Terraform state to simulate a lost or corrupted state file:

terraform state rm random_string.suffix
Removed random_string.suffix
Successfully removed 1 resource instance(s).

Run terraform plan to see what Terraform would do without the state entry:

terraform plan
Terraform will perform the following actions:

  # random_string.suffix will be created
  + resource "random_string" "suffix" {
      + id      = (known after apply)
      + length  = 8
      ...
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Terraform would generate a brand-new random string — a completely different value — which would break any existing resource names that rely on the original suffix. This is the problem that terraform import solves.

Step 5.5.3: Import with a CLI command

Before Terraform 1.5, importing an existing resource into state required the terraform import CLI command. Use the $SUFFIX variable you captured earlier as the import ID:

terraform import random_string.suffix "$SUFFIX"
random_string.suffix: Importing from ID "k7m2px4n"...
random_string.suffix: Import prepared!
  Prepared random_string for import
random_string.suffix: Refreshing state... [id=k7m2px4n]

Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.

Now run terraform plan to verify no changes are detected:

terraform plan
No changes. Your infrastructure matches the configuration.

Explanation

terraform import <resource_address> <provider-specific-id> reads the current state of the existing resource from the provider and writes it into the Terraform state file. The resource configuration in .tf files must already exist before importing — the command does not generate configuration for you.

The <provider-specific-id> is provider-dependent. For random_string it is the string value itself; for an AWS S3 bucket it would be the bucket name; for an Azure resource group it would be the full resource ID.

Step 5.5.4: Import block (Terraform ≥ 1.5)

Terraform 1.5 introduced a declarative import block that integrates the import into a normal plan/apply workflow and eliminates the need for a separate CLI step.

Remove the existing state entry first so we can demonstrate importing afresh:

terraform state rm random_string.suffix

Add the following import block to main.tf, replacing <your-suffix> with the value you saved earlier (e.g. k7m2px4n):

import {
  to = random_string.suffix
  id = "<your-suffix>"
}

Now run plan and apply:

terraform plan
terraform apply

Terraform imports the resource during the apply. Once the import is complete you can remove the import block from main.tf — or leave it in place, as it becomes a no-op on subsequent applies once the resource is in state.

Explanation

The import block approach has several advantages over the CLI command:

  • It is reviewable in a pull request like any other code change.
  • It works inside CI/CD pipelines without extra shell scripting.
  • Terraform 1.6+ can also generate the resource configuration automatically with terraform plan -generate-config-out=generated.tf, reducing manual effort when importing large numbers of resources.