The import block (Terraform 1.5+) lets you bring existing infrastructure under Terraform management without CLI commands. Write it in HCL, run terraform plan, and Terraform generates the import plan. This replaces the old terraform import CLI workflow for most use cases.
Import Block vs CLI Import
Old Way: CLI Import
# One resource at a time, imperative
terraform import aws_instance.web i-0abc123def456
terraform import aws_s3_bucket.data my-bucket-name
terraform import aws_vpc.main vpc-0abc123
Problems:
- Must run manually, one resource at a time
- No plan preview — imports immediately
- Not version-controlled
- Can’t be code-reviewed in a PR
New Way: Import Block
# Declarative, code-reviewed, bulk-capable
import {
to = aws_instance.web
id = "i-0abc123def456"
}
import {
to = aws_s3_bucket.data
id = "my-bucket-name"
}
import {
to = aws_vpc.main
id = "vpc-0abc123"
}
terraform plan # Shows what will be imported — no changes yet
terraform apply # Imports into state
Basic Usage
Step 1: Write the Import Block
# imports.tf
import {
to = aws_instance.web
id = "i-0abc123def456"
}
Step 2: Write the Resource Configuration
# main.tf
resource "aws_instance" "web" {
ami = "ami-abc123"
instance_type = "t3.micro"
subnet_id = "subnet-xyz789"
tags = {
Name = "web-server"
}
}
Step 3: Plan and Apply
terraform plan
# aws_instance.web: Importing...
# Plan: 1 to import, 0 to add, 0 to change, 0 to destroy
terraform apply
# aws_instance.web: Importing... [id=i-0abc123def456]
# Import successful!
Step 4: Remove the Import Block
After applying, the import block is no longer needed:
# imports.tf — can be deleted after successful import
# import {
# to = aws_instance.web
# id = "i-0abc123def456"
# }
Auto-Generate Configuration
Don’t want to write the resource block manually? Use -generate-config-out:
terraform plan -generate-config-out=generated.tf
This creates generated.tf with the full resource configuration based on the actual cloud resource:
# generated.tf (auto-generated)
resource "aws_instance" "web" {
ami = "ami-abc123"
instance_type = "t3.micro"
subnet_id = "subnet-xyz789"
vpc_security_group_ids = ["sg-abc123"]
associate_public_ip_address = true
key_name = "my-key"
root_block_device {
volume_size = 20
volume_type = "gp3"
encrypted = true
}
tags = {
Name = "web-server"
}
}
Review and clean up the generated config (remove computed attributes, add variables), then apply.
Bulk Import
Import many resources at once:
# Import an entire VPC setup
import {
to = aws_vpc.main
id = "vpc-0abc123"
}
import {
to = aws_subnet.public[0]
id = "subnet-pub1"
}
import {
to = aws_subnet.public[1]
id = "subnet-pub2"
}
import {
to = aws_subnet.private[0]
id = "subnet-priv1"
}
import {
to = aws_subnet.private[1]
id = "subnet-priv2"
}
import {
to = aws_internet_gateway.main
id = "igw-xyz789"
}
import {
to = aws_nat_gateway.main
id = "nat-abc456"
}
import {
to = aws_route_table.public
id = "rtb-pub123"
}
import {
to = aws_route_table.private
id = "rtb-priv456"
}
# Generate config for all
terraform plan -generate-config-out=generated_vpc.tf
# Review, clean up, then apply
terraform apply
Import with for_each
locals {
existing_buckets = {
logs = "company-logs-bucket"
data = "company-data-bucket"
backups = "company-backups-bucket"
}
}
import {
for_each = local.existing_buckets
to = aws_s3_bucket.imported[each.key]
id = each.value
}
resource "aws_s3_bucket" "imported" {
for_each = local.existing_buckets
bucket = each.value
}
Common Import IDs by Resource
| Resource | Import ID Format | Example |
|---|---|---|
aws_instance | Instance ID | i-0abc123def456 |
aws_s3_bucket | Bucket name | my-bucket |
aws_vpc | VPC ID | vpc-0abc123 |
aws_subnet | Subnet ID | subnet-xyz789 |
aws_security_group | SG ID | sg-abc123 |
aws_db_instance | DB identifier | my-database |
aws_iam_role | Role name | my-role |
aws_route53_zone | Zone ID | Z1234567890 |
aws_lambda_function | Function name | my-function |
aws_ecs_cluster | Cluster ARN | arn:aws:ecs:... |
Tips and Gotchas
Plan Shows Changes After Import
This is normal — the imported resource may differ from your written config:
terraform plan
# aws_instance.web will be updated in-place
# ~ instance_type = "t3.micro" -> "t3.small"
Fix: update your HCL to match the actual resource, or accept the planned change.
Attributes You Can’t Set
Some attributes are read-only (computed). Remove them from generated config:
resource "aws_instance" "web" {
# Remove these — they're computed
# arn = "arn:aws:ec2:..."
# id = "i-0abc123"
# public_ip = "1.2.3.4"
ami = "ami-abc123"
instance_type = "t3.micro"
}
Import Doesn’t Create Resources
Import only adds existing resources to state. It never creates, modifies, or deletes the actual cloud resource during the import step.
Hands-On Courses
- Terraform for Beginners on CopyPasteLearn
- Terraform By Example — practical code examples
Conclusion
The import block replaces terraform import CLI for most workflows. It’s declarative, code-reviewable, and supports bulk imports. Use -generate-config-out to auto-generate resource configurations, then clean up and apply. Remove import blocks after successful import — they’re one-time use.