7.1.1. terraform import and Import Blocks
💡 First Principle: Import is fundamentally a state operation — it binds an existing real resource to a configuration address — so the address you import to must already have a matching resource block before the classic command will run, or Terraform will plan to destroy the unmanaged-looking entry.
The classic CLI command maps one real resource ID to one configuration address:
terraform import aws_instance.web i-1234567890abcdef0
The resource "aws_instance" "web" block must already exist before you run this — classic import errors out if the address is not in configuration. The command writes the resource into state but does not create or edit configuration; if the block's arguments don't match reality, if its arguments don't match reality, the next plan shows changes.
Import blocks (Terraform 1.5+) make import declarative and reviewable:
import {
to = aws_instance.web
id = "i-1234567890abcdef0"
}
Because they live in configuration, import blocks are planned (you see the import in terraform plan), version-controlled, and can import many resources at once — a big improvement over the imperative command.
⚠️ Exam Trap: Classic terraform import imports into state only, one resource at a time, and never generates config. Import blocks are declarative, plannable, and support bulk import. Don't attribute config generation to the classic command.
Reflection Question: You write an empty resource block, run classic terraform import against it, and the next terraform plan is not a clean no-op. What does it propose, and why does that differ from what happens if the block is later deleted altogether?