Skip to main content
terraform import: Bring Existing Resources Under Terraform Management

terraform import: Bring Existing Resources Under Terraform Management

Key Takeaway

Step-by-step guide to terraform import. Import existing AWS, Azure, and GCP resources into Terraform state. Includes import blocks (Terraform 1.5+)

Table of Contents

Introduction

You have cloud resources running in production that weren’t created with Terraform. Maybe they were created manually in the AWS console, or through a different tool. Now you want to manage them with Terraform without recreating them.

That’s exactly what terraform import does — it brings existing infrastructure under Terraform management by adding it to the state file.

Quick Start

Import an existing AWS EC2 instance:

# 1. Write the resource block in your .tf file
# main.tf
resource "aws_instance" "web" {
  # Configuration will be filled after import
}

# 2. Import the resource
terraform import aws_instance.web i-1234567890abcdef0

# 3. Verify the import
terraform state show aws_instance.web

# 4. Fill in the configuration to match the actual resource
# Run terraform plan — it should show "No changes"

Two Methods: CLI Import vs Import Blocks

Method 1: terraform import Command (All Versions)

The classic approach — one resource at a time:

terraform import <resource_type>.<name> <resource_id>

Examples:

# AWS EC2 instance
terraform import aws_instance.web i-1234567890abcdef0

# AWS S3 bucket
terraform import aws_s3_bucket.data my-bucket-name

# AWS Security Group
terraform import aws_security_group.web sg-0123456789abcdef0

# AWS VPC
terraform import aws_vpc.main vpc-0123456789abcdef0

# Azure Resource Group
terraform import azurerm_resource_group.main /subscriptions/SUB_ID/resourceGroups/my-rg

# GCP Compute Instance
terraform import google_compute_instance.web projects/my-project/zones/us-central1-a/instances/my-vm

Method 2: Import Blocks (Terraform 1.5+)

Import blocks are declarative — add them to your .tf files and run terraform plan:

# imports.tf
import {
  to = aws_instance.web
  id = "i-1234567890abcdef0"
}

import {
  to = aws_s3_bucket.data
  id = "my-bucket-name"
}

import {
  to = aws_security_group.web
  id = "sg-0123456789abcdef0"
}

Then run:

terraform plan -generate-config-out=generated.tf

Terraform generates the configuration automatically. Review generated.tf, clean it up, and merge it into your main configuration.

Advantages of import blocks:

  • Can import multiple resources at once
  • Configuration can be auto-generated
  • Import is part of the plan/apply workflow
  • Works with Terraform Cloud

Step-by-Step: Import an AWS EC2 Instance

Step 1: Find the Resource ID

aws ec2 describe-instances --filters "Name=tag:Name,Values=my-server" \
  --query "Reservations[].Instances[].InstanceId" --output text

Output: i-0abc123def456789

Step 2: Write the Resource Block

Create a minimal resource block in your .tf file:

resource "aws_instance" "web" {
  # Required attributes — we'll fill these after import
  ami           = "ami-placeholder"
  instance_type = "t3.micro"
}

Step 3: Run the Import

terraform import aws_instance.web i-0abc123def456789

Output:

aws_instance.web: Importing from ID "i-0abc123def456789"...
aws_instance.web: Import prepared!
  Prepared aws_instance for import
aws_instance.web: Refreshing state... [id=i-0abc123def456789]

Import successful!

Step 4: Get the Full Configuration

terraform state show aws_instance.web

This prints all attributes. Copy the relevant ones into your resource block:

resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"
  subnet_id     = "subnet-0123456789abcdef0"
  key_name      = "my-key"

  vpc_security_group_ids = ["sg-0123456789abcdef0"]

  root_block_device {
    volume_size = 20
    volume_type = "gp3"
  }

  tags = {
    Name = "my-server"
  }
}

Step 5: Verify — No Changes

terraform plan

Should show:

No changes. Your infrastructure matches the configuration.

If it shows changes, update your configuration to match the actual resource state.

Bulk Import: Multiple Resources

# imports.tf — import your entire VPC setup
import {
  to = aws_vpc.main
  id = "vpc-0123456789"
}

import {
  to = aws_subnet.public_a
  id = "subnet-aaa111"
}

import {
  to = aws_subnet.public_b
  id = "subnet-bbb222"
}

import {
  to = aws_internet_gateway.main
  id = "igw-0123456789"
}

import {
  to = aws_route_table.public
  id = "rtb-0123456789"
}
terraform plan -generate-config-out=generated_vpc.tf

Using a Shell Script

For many resources of the same type:

#!/bin/bash
# Import all EC2 instances with a specific tag
INSTANCES=$(aws ec2 describe-instances \
  --filters "Name=tag:Environment,Values=production" \
  --query "Reservations[].Instances[].InstanceId" \
  --output text)

i=0
for id in $INSTANCES; do
  terraform import "aws_instance.prod[$i]" "$id"
  ((i++))
done

Import for Different Cloud Providers

AWS Common Resources

# VPC
terraform import aws_vpc.main vpc-12345

# Subnet
terraform import aws_subnet.public subnet-12345

# Security Group
terraform import aws_security_group.web sg-12345

# RDS Instance
terraform import aws_db_instance.main my-database

# IAM Role
terraform import aws_iam_role.lambda my-lambda-role

# S3 Bucket
terraform import aws_s3_bucket.logs my-log-bucket

# Route53 Zone
terraform import aws_route53_zone.main Z1234567890

Azure Common Resources

# Resource Group
terraform import azurerm_resource_group.main \
  /subscriptions/SUB_ID/resourceGroups/my-rg

# Virtual Network
terraform import azurerm_virtual_network.main \
  /subscriptions/SUB_ID/resourceGroups/my-rg/providers/Microsoft.Network/virtualNetworks/my-vnet

# Storage Account
terraform import azurerm_storage_account.main \
  /subscriptions/SUB_ID/resourceGroups/my-rg/providers/Microsoft.Storage/storageAccounts/mystorageaccount

GCP Common Resources

# Compute Instance
terraform import google_compute_instance.web \
  projects/my-project/zones/us-central1-a/instances/my-vm

# GKE Cluster
terraform import google_container_cluster.primary \
  projects/my-project/locations/us-central1/clusters/my-cluster

# Cloud Storage Bucket
terraform import google_storage_bucket.data my-bucket

Common Errors and Fixes

“Resource already managed by Terraform”

Error: Resource already managed by Terraform

The resource is already in your state. Check with:

terraform state list | grep aws_instance

“Cannot import non-existent remote object”

Error: Cannot import non-existent remote object

The resource ID is wrong or the resource was deleted. Verify it exists:

aws ec2 describe-instances --instance-ids i-1234567890abcdef0

Configuration drift after import

If terraform plan shows changes after import, your .tf configuration doesn’t match the real resource. Update your config to match, or accept the drift by running apply.

Best Practices

  1. Import to a separate state first: Test imports in a workspace before importing into production state
  2. Use import blocks (Terraform 1.5+): They’re declarative, reviewable, and support auto-generated configs
  3. Run plan immediately after import: Verify no unexpected changes
  4. Back up your state: cp terraform.tfstate terraform.tfstate.backup before importing
  5. Don’t import and modify in the same apply: Import first, verify, then make changes
  6. Tag resources before importing: Makes identification easier
  7. Remove import blocks after apply: They’re only needed for the initial import

Hands-On Courses

Learn by doing with interactive courses on CopyPasteLearn:

Conclusion

terraform import bridges the gap between manually created infrastructure and Terraform management. Use the CLI command for quick one-off imports, and import blocks (Terraform 1.5+) for bulk imports with auto-generated configurations. Always verify with terraform plan after importing to ensure your configuration matches the real infrastructure.

🚀

Level Up Your Terraform Skills

Hands-on courses, books, and resources from Luca Berton

Luca Berton
Written by

Luca Berton

DevOps Engineer, AWS Partner, Terraform expert, and author. Creator of Ansible Pilot, Terraform Pilot, and CopyPasteLearn.