What Is Terraform Import?
You joined a company where the entire AWS account was built by clicking in the console over three years. There are 200 EC2 instances, 50 S3 buckets, and a VPC with 30 subnets — none of it managed by Terraform. The team wants to adopt Terraform without destroying and recreating everything.
terraform import is how you do it. It reads an existing cloud resource and writes its current state into the Terraform state file. Once imported, Terraform knows the resource exists. You can then write HCL that matches it, and Terraform will manage all future changes through code.
REMEMBER THIS**Remember:** `terraform import` adds the resource to state — it does NOT write the HCL configuration for you (except with the newer `-generate-config-out` flag in Terraform 1.5+). You still need to write the resource block yourself.
The Classic Two-Step Import Process
Step 1 — Write the Resource Configuration
Write a resource block in your .tf files that matches the existing resource. You do not need every argument yet — just enough to make Terraform accept the block:
# main.tf — write this BEFORE running terraform importresource "aws_instance" "payments_api" { # Arguments will be filled in after import # The block just needs to exist for import to work ami = "ami-0f5ee92e2d63afc18" # fill in the real values instance_type = "t3.medium" tags = { Name = "razorpay-payments-api-prod" }}Step 2 — Run terraform import
# Syntax: terraform import <resource_type>.<resource_name> <real_resource_id>terraform import aws_instance.payments_api i-0a1b2c3d4e5f6789 # aws_instance.payments_api: Importing from ID "i-0a1b2c3d4e5f6789"...# aws_instance.payments_api: Import prepared!# Prepared aws_instance for import# aws_instance.payments_api: Refreshing state... [id=i-0a1b2c3d4e5f6789]## 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.Step 3 — Run terraform plan and Fix Mismatches
After import, run terraform plan. It will show differences between what you wrote in HCL and what is actually on the resource. Fix each difference:
terraform plan # ~ aws_instance.payments_api will be updated in-place# ~ instance_type = "t3.medium" -> "t3.large" <- real instance is t3.large# ~ monitoring = false -> true <- real instance has monitoring on## Fix your HCL to match the real resource, then re-plan until the output is:# No changes. Your infrastructure matches the configuration.Finding the Resource ID for Common AWS Resources
# EC2 Instanceaws ec2 describe-instances --filters "Name=tag:Name,Values=razorpay-payments-api"# ID format: i-0a1b2c3d4e5f6789terraform import aws_instance.payments_api i-0a1b2c3d4e5f6789 # S3 Bucket# ID is just the bucket nameterraform import aws_s3_bucket.assets razorpay-assets-prod # Security Groupaws ec2 describe-security-groups --filters "Name=group-name,Values=payments-api-sg"# ID format: sg-0a1b2c3d4e5f6789terraform import aws_security_group.payments sg-0a1b2c3d4e5f6789 # RDS Instance# ID is the DB identifierterraform import aws_db_instance.main razorpay-payments-postgres-prod # IAM Role# ID is the role nameterraform import aws_iam_role.app_role razorpay-payments-api-role # VPCaws ec2 describe-vpcs --filters "Name=tag:Name,Values=razorpay-prod-vpc"# ID format: vpc-0a1b2c3d4e5fterraform import aws_vpc.main vpc-0a1b2c3d4e5fThe New Import Block (Terraform 1.5+)
Terraform 1.5 introduced a declarative import block that lives in your .tf files — no CLI command needed. Import happens automatically during terraform apply:
# imports.tf — declarative import (Terraform 1.5+)import { to = aws_instance.payments_api id = "i-0a1b2c3d4e5f6789"} import { to = aws_s3_bucket.assets id = "razorpay-assets-prod"}Auto-Generating HCL with -generate-config-out (Terraform 1.5+)
Terraform 1.5 can generate the HCL resource block automatically from an import block:
# Add an import block with no corresponding resource block# Then run:terraform plan -generate-config-out=generated.tf # Terraform reads the real resource and writes HCL into generated.tf# Review and clean up generated.tf — it includes every attribute# including computed ones you do not need to specifyTroubleshooting Import
| Error | Root Cause | Fix |
|---|---|---|
Resource already managed by Terraform |
Resource already in state | Check terraform state list — may already be imported |
Cannot import non-existent remote object |
Wrong resource ID | Verify the ID in the AWS console or CLI |
Error: Resource type does not support import |
Provider does not support import | Check the provider docs — not all resources are importable |
| Plan shows large diff after import | HCL does not match real resource | Run terraform state show to see all attributes, update HCL to match |
InvalidInstanceID.NotFound |
Wrong EC2 instance ID format | Must start with i- followed by hex characters |
COMMON MISTAKE / WARNING**Common Mistake:** Running `terraform apply` immediately after import without checking the plan. If your HCL does not exactly match the real resource, apply will change the resource to match your code — potentially disabling security settings or changing production configuration.