Importing Existing Infrastructure
Real organizations rarely start with a blank slate — resources are often created manually through a cloud console, by a legacy script, or by a different tool entirely, long before Terraform enters the picture. Importing is the process of associating one of these pre-existing resources with a resource block in configuration so that Terraform's state file records it, without Terraform ever having to create (or, worse, accidentally destroy and recreate) it. Import only populates state; it does not generate configuration for you, which means the corresponding resource block in your .tf files must already exist and its arguments must be written to accurately reflect the real object's current settings.
Cricket analogy: A franchise doesn't always draft players from scratch; sometimes a veteran already playing domestic cricket is added to the roster, and the team registry must record their existing stats without pretending they're a debutant.
The Two-Step Workflow
The classic workflow is: first write (or stub out) a resource block with the right type and a local name, then run terraform import <resource_address> <external_id>, where the external ID format is resource-type-specific (an AWS instance ID, an Azure resource ID, a GCP self-link, etc.). After the import command succeeds, running terraform plan will almost certainly show a diff, because your hand-written configuration rarely matches every real attribute exactly on the first try — you then iteratively adjust the configuration until plan reports no changes, confirming that configuration and real-world state now agree.
Cricket analogy: First a scorer writes a placeholder name on the sheet, then cross-checks the player's actual identity via the toss card; the first plan rarely matches perfectly, so the scorer amends it entry by entry until it's accurate.
The import Block (Terraform 1.5+)
Since Terraform 1.5, an import block can be declared directly in configuration as a declarative alternative to the imperative terraform import CLI command. This has the advantage of being reviewable in a pull request and repeatable across environments, and combined with terraform plan -generate-config-out=generated.tf, Terraform can even scaffold a starting resource configuration automatically from the real object's attributes, dramatically reducing the manual transcription work for large migrations.
Cricket analogy: Modern scoring apps let a scorer declare a player's stats directly from a structured template instead of writing longhand, and can even auto-fill career figures from the official database, cutting manual transcription drastically.
# Classic imperative import
$ terraform import aws_s3_bucket.assets acme-prod-assets-bucket
aws_s3_bucket.assets: Importing from ID "acme-prod-assets-bucket"...
aws_s3_bucket.assets: Import prepared!
Prepared aws_s3_bucket for import
aws_s3_bucket.assets: Refreshing state... [id=acme-prod-assets-bucket]
Import successful!# Declarative import block (Terraform 1.5+)
import {
to = aws_s3_bucket.assets
id = "acme-prod-assets-bucket"
}
resource "aws_s3_bucket" "assets" {
bucket = "acme-prod-assets-bucket"
}
# terraform plan -generate-config-out=generated.tfImport is like retroactively filing paperwork for a building that was already constructed: the building doesn't change, but now it officially appears in the city's records and future permits (Terraform plans) will account for it correctly.
If the resource block's arguments don't match the real object closely enough after import, the very next apply can attempt to 'correct' the mismatch — potentially modifying or even replacing the resource in-place. Always run terraform plan immediately after an import and scrutinize every proposed change before applying.
- Import associates a pre-existing real-world resource with a Terraform resource block, populating state without recreating the object.
- Import does not generate configuration automatically in classic usage — the resource block must already exist and be written by hand.
- The external ID format required for import is resource-type-specific and provider-documented.
- After import, terraform plan almost always shows a diff until the configuration is manually reconciled to match reality.
- Terraform 1.5+ import blocks provide a declarative, reviewable alternative to the imperative terraform import command.
- -generate-config-out can scaffold starting configuration automatically from imported resource attributes.
Practice what you learned
1. What does terraform import actually do to your .tf configuration files?
2. What should you do immediately after successfully importing a resource?
3. What Terraform version introduced the declarative import block?
4. What does the -generate-config-out flag do when used with terraform plan alongside an import block?
5. What is the risk if an imported resource's configuration doesn't closely match the real object's actual settings?
Was this page helpful?
You May Also Like
The Terraform State File
Terraform's state file is the source of truth mapping your configuration to real-world resources. Understanding its structure and risks is essential for safe, collaborative infrastructure management.
Refactoring State with moved Blocks
The moved block lets Terraform track renamed or relocated resources declaratively, avoiding destructive replace plans when refactoring configuration.
Drift Detection
Understand configuration drift — when real infrastructure diverges from Terraform state — and the tools and practices used to detect and reconcile it before it causes surprises.
Resources and Resource Blocks
The resource block is Terraform's fundamental unit of infrastructure declaration, describing a single managed object like a virtual machine, network, or storage bucket.
Related Reading
Related Study Notes in DevOps
Browse all study notesNginx Study Notes
DevOps · 30 topics
DevOpsAnsible Study Notes
DevOps · 30 topics
DevOpsAdvanced Kubernetes Study Notes
Kubernetes · 30 topics
DevOpsAdvanced Bash Scripting Study Notes
Bash · 30 topics
DevOpsApache Kafka Study Notes
Kafka · 30 topics
DevOpsDocker & Kubernetes Study Notes
YAML · 40 topics