Import existing infrastructure
The classic terraform import CLI command
You created a storage bucket by hand months ago, and now you want Terraform to own it without tearing it down and rebuilding. The original tool for that is terraform import[1], the command that binds one already-existing remote object to a resource address in your configuration by recording it in Terraform state[2]. It changes nothing in the real world: it only teaches Terraform that the object exists and which address manages it from now on. This section covers the command's two positional arguments, why the target resource block has to exist before you run it, and the fact that import writes only to state.
Write the resource block first
The command takes exactly two positional arguments:
terraform import ADDRESS ID
ADDRESS is the resource address[3] in your configuration, such as aws_s3_bucket.assets, and ID is the provider's own identifier for the real object, such as the bucket name. The ID format is defined by the resource type, not chosen by Terraform, so each resource type's documentation states what its import ID looks like.
Because the command binds an object to an address, that resource block must already exist. Importing via the CLI does not generate configuration[4]: point terraform import at an address with no matching resource block and it fails. The normal routine is to write a skeleton resource block, run the import, then run terraform plan and fill in arguments until the plan reports no changes, which is the signal that your configuration now matches the imported object.
It only writes state
terraform import can only import resources into state[4]. It does not create, update, or destroy real infrastructure, and it does not write any HCL for you. It also imports one object per invocation, so adopting ten objects means running the command ten times. There is no provider-specific variant such as terraform import-aws, and terraform refresh[5] does not help either: refresh only reconciles state for resources Terraform already manages and never discovers or adopts an unmanaged object.
Config-driven import blocks
Running one CLI command per object does not fit code review or a large migration, so Terraform 1.5 introduced the import block[6]: a way to declare imports in configuration and run them through the ordinary workflow. An import block names where the object goes and what it is.
import {
to = aws_s3_bucket.assets
id = "my-existing-bucket"
}
to and id
The to argument[7] is the resource address to import into, and the id argument is the cloud provider's identifier for the existing object. Do not swap them: to is the Terraform address, id is the real object's provider ID. The id must be a string or an expression that is known at plan time[7], so it can reference an input variable but cannot depend on a value that is only known after apply. A single block imports one object; adding for_each[7] to the block imports a whole map or set of similar objects without a separate block for each.
Plan and apply, then delete the block
An import block runs through the normal plan and apply workflow[6]: terraform plan shows the import alongside any other planned changes, and terraform apply carries it out. There is no separate import subcommand. Like the CLI command, the import block only affects state; the real object is untouched. By default the to address must still match a resource block you have written, so the one way to skip writing that block first is configuration generation, covered in the next section. Because the block does nothing once the object is in state, you can remove it after a successful apply[6] without destroying the resource, and the common practice is to delete import blocks once the migration is done so the configuration is not cluttered with one-time instructions.
Generating configuration with -generate-config-out
Writing the resource block by hand is the tedious part of an import, especially for a resource with dozens of arguments. The config-driven path can produce a first draft for you: run terraform plan -generate-config-out=FILE[8] with an import block whose to points at a resource that does not yet exist in your configuration, and Terraform writes generated HCL for that object into the named file.
A plan-time feature of import blocks, not the CLI
Configuration generation is a feature of import blocks reached through terraform plan; the classic terraform import CLI command cannot generate configuration[4]. The FILE must be a new path: supplying a path to an existing file makes Terraform error[8] rather than overwrite your work. Once the plan has written the file, terraform apply completes the import.
Review before you apply
The output is Terraform's best guess at the value for each resource argument[8]: a template to iterate on by removing some attributes, adjusting the value of others, and rearranging blocks, not a finished module. For some resources Terraform cannot construct a valid configuration and emits blocks that need manual fixes, and not every provider supports generation. Review and edit the generated file before you apply it.
Exam-pattern recognition
Import questions turn on a few sharp distinctions between the two mechanisms. Match the stem to the mechanism.
- A stem says import will write the configuration for you. That is false for the CLI:
terraform importonly updates state, so theresourceblock must already exist. Configuration generation is a feature of the config-drivenimportblock viaterraform plan -generate-config-out=FILE, not of the classic command. - A stem asks how to import many resources, or to keep imports in version control and code review. The answer is
importblocks, not a loop of CLI commands: blocks are declarative, reviewable, and supportfor_each, whereasterraform importimports one object per invocation. - A stem swaps
toandid, or asks which is which.tois the Terraform resource address;idis the provider's own identifier for the existing object, and its format is set by the resource type. - A stem invents a command like
terraform import-gcp, or claimsterraform refreshadopts unmanaged resources. Both are wrong. The only ways to bring existing infrastructure under management areterraform import ADDRESS IDand theimportblock; refresh only updates resources already in state. - A stem asks whether you can delete an import block afterward. Yes. An import block only affects state, so removing it after a successful apply does not destroy the resource.
- A stem treats generated configuration as ready to apply. It is a starting point: review and edit it first, because generated blocks may include attributes that need adjustment to produce a clean plan.
Classic terraform import CLI vs the config-driven import block
| Aspect | terraform import (CLI) | import block (config-driven) |
|---|---|---|
| Added in | Early Terraform | Terraform 1.5 |
| What it writes | State only | State only |
| Generates configuration? | No; write the resource block first | Optionally, via terraform plan -generate-config-out |
| How it runs | terraform import ADDRESS ID | terraform plan, then terraform apply |
| Import many at once? | No; one object per command | Yes; one block each or for_each |
| Removable after use? | Not in configuration | Yes; remove the block after a successful apply |
Decision tree
Sharp facts the exam loves — give these one last read before exam day.
Cheat sheet
Sharp facts the exam loves — scan these before test day.
- Import requires a pre-existing resource block
Before running
terraform import ADDRESS ID, you must already have written the targetresourceblock in your configuration; the classic CLI import binds an existing object to that pre-existing address and cannot import into an address that has no matching resource block.Trap Assuming terraform import writes the resource block for you — it only updates state, so the configuration must exist first.
4 questions test this
- Before importing an existing database instance, an engineer adds an empty `resource "aws_db_instance" "main" {}` block with no arguments filled in, then runs `terraform import aws_db_instance.main <id
- An engineer wrote a `resource "aws_instance" "web"` block and then ran `terraform import aws_instance.web i-0abc123def456`, which completed successfully. Reviewing the result, a colleague claims Terra
- Your team is documenting the correct order of steps for importing a hand-built load balancer into Terraform. One engineer claims you can run `terraform import` first and add the `resource` block after
- A platform engineer wants to bring a hand-created object under Terraform management. In an otherwise empty working directory she immediately runs `terraform import aws_instance.web i-0abc123def`, and
- Two positional arguments: ADDRESS and ID
terraform importtakes exactly two positional arguments,terraform import ADDRESS ID, where ADDRESS is the resource address in your configuration and ID is the provider-specific identifier of the real object; the ID format varies by resource type.Trap Thinking the ID is a Terraform-chosen name — it is the provider's own object identifier and differs per resource type.
3 questions test this
- An engineer runs `terraform import aws_instance.web` and Terraform errors out asking for more input. She then tries `terraform import aws_instance.web i-0abc123 vpc-0def456`, which also fails. How man
- An engineer is importing an existing AWS EC2 instance and asks what value to supply as the `ID` positional argument in `terraform import aws_instance.web ID`. She wonders whether she gets to pick a fr
- During a migration an engineer needs to import an existing Route 53 hosted zone that was created by hand, and he has already written the matching `resource` block in his configuration. The `terraform
- CLI import only writes state
The
terraform importCLI command only records the existing object in Terraform state; it does not generate configuration and does not create, modify, or destroy any real infrastructure.Trap Expecting import to auto-generate HCL — the classic CLI command never generates configuration.
5 questions test this
- An engineer runs `terraform import aws_s3_bucket.logs my-logs-bucket` against a bucket that already holds production data, after writing the matching resource block. A teammate worries the command mig
- An engineer wrote a `resource "aws_instance" "web"` block and then ran `terraform import aws_instance.web i-0abc123def456`, which completed successfully. Reviewing the result, a colleague claims Terra
- A team wants Terraform to write the HCL for dozens of existing resources automatically rather than hand-authoring every `resource` block. They ask whether the classic `terraform import` CLI command ca
- Your team is documenting the correct order of steps for importing a hand-built load balancer into Terraform. One engineer claims you can run `terraform import` first and add the `resource` block after
- A platform engineer wants to bring a hand-created object under Terraform management. In an otherwise empty working directory she immediately runs `terraform import aws_instance.web i-0abc123def`, and
- No provider-specific import command
There is no provider-specific import command such as
terraform import-gcp, andterraform refreshdoes not adopt unmanaged objects; the only CLI way to bring existing infrastructure under management isterraform import ADDRESS ID(or a config-driven import block).Trap Believing a command like terraform import-gcp exists or that terraform refresh discovers and adopts unmanaged resources.
3 questions test this
- A team wants Terraform to write the HCL for dozens of existing resources automatically rather than hand-authoring every `resource` block. They ask whether the classic `terraform import` CLI command ca
- Someone on your team created several servers directly in the cloud console. A colleague suggests running `terraform refresh` so Terraform will detect those new servers and begin managing them. Before
- A teammate insists that because your infrastructure runs on Google Cloud, you should adopt an existing GCP object with a provider-specific command such as `terraform import-gcp`. You need to correct t
- import block uses to and id
The configuration-driven
importblock (Terraform 1.5+) declares an import with two arguments:to, the resource address to import into, andid, the provider-specific identifier of the existing object.Trap Swapping the arguments —
tois the Terraform resource address andidis the real object's provider ID, not the reverse.7 questions test this
- An engineer writes an import block whose id argument references an attribute of another resource that Terraform has not created yet, so the value is unknown until apply. When they run terraform plan,
- A platform engineer writes two import blocks in one configuration: one adopts an existing storage bucket and the other adopts an existing virtual machine. The value each block assigns to its id argume
- A platform engineer wants to bring an existing S3 bucket named prod-assets under Terraform management by binding it to the aws_s3_bucket.assets resource block that already exists in the configuration.
- A team successfully imported an existing resource using an import block plus its matching resource block and then ran terraform apply. A new engineer asks whether the import block must remain in the c
- An engineer's import fails. Their block reads to = "vol-0f9a2" and id = aws_ebs_volume.data, where vol-0f9a2 is the real EBS volume's identifier and aws_ebs_volume.data is the resource block in their
- An engineer wants to bring an existing database instance, whose provider-assigned identifier is prod-db-01, under Terraform management by importing it into the resource address aws_db_instance.prod. W
- An engineer adds an import block containing to = aws_iam_role.ci and id = "ci-deploy-role", but the configuration does not yet contain any resource block at that address. When they run terraform plan,
- Import blocks run through plan and apply
An
importblock is executed through the normal workflow:terraform planpreviews the planned import andterraform applyperforms it; there is no separate import subcommand, and theidmust be a literal or known value at plan time.Trap Thinking import blocks need a special command — they are planned and applied like any other configuration change.
8 questions test this
- An engineer writes an import block whose id argument references an attribute of another resource that Terraform has not created yet, so the value is unknown until apply. When they run terraform plan,
- A DevOps engineer adds an import block for an existing production VPC and then runs terraform plan with no extra flags. Before any changes are made to state, what does Terraform show for that import b
- A team runs Terraform in a CI/CD pipeline against HCP Terraform and wants to adopt several existing resources in a way that can be reviewed in a pull request before any state changes. Why is a config-
- A teammate has added an import block to your configuration to adopt an existing resource, and the matching resource block is already present. Following the config-driven import workflow, which single
- A team successfully imported an existing resource using an import block plus its matching resource block and then ran terraform apply. A new engineer asks whether the import block must remain in the c
- A DevOps engineer is used to adopting resources by running terraform import ADDRESS ID on the command line. They switch to a config-driven import block that already has a matching resource block. Whic
- A team successfully imported an existing resource using an import block and terraform apply. The next day a colleague runs terraform plan again with the same import block still in the configuration. W
- An engineer's configuration contains one import block for an existing network object plus two brand-new resource blocks that do not exist in the provider yet. After reviewing terraform plan, they run
- Import blocks can be removed after apply
Because an
importblock only affects state (recording an existing object at its address), you can safely remove the block from configuration after a successful apply without destroying the resource.- -generate-config-out generates HCL
Running
terraform plan -generate-config-out=<FILE>together with animportblock generates HCLresourceconfiguration for the imported objects into the given file; this config generation is a feature of import blocks, not of the classicterraform importCLI command.Trap Trying to use -generate-config-out with the classic terraform import CLI command — only the config-driven import block supports generated configuration.
11 questions test this
- An operations team must bring roughly forty manually-created cloud objects under Terraform management and wants to avoid hand-authoring a `resource` block for each one. Which approach lets Terraform d
- After adding `import` blocks for three legacy VPCs, an engineer runs `terraform plan -generate-config-out=vpcs.tf` and it completes without error. When she opens the new `vpcs.tf` file, what will it c
- Terraform documents two ways to import existing infrastructure: the imperative `terraform import` CLI command and the config-driven `import` block. A colleague asks which of the two can also generate
- An engineer ran `terraform import aws_s3_bucket.logs my-logs-bucket` to bring an existing bucket under management and expected Terraform to also write a `.tf` file containing the bucket's `resource` c
- A teammate generated resource configuration with `terraform plan -generate-config-out=main-generated.tf` and proposes running `terraform apply` against it immediately, assuming the output is productio
- A team has added `import` blocks, run `terraform plan -generate-config-out=new.tf`, and reviewed and edited the generated configuration. Which command do they run next to actually import the objects i
- Your configuration currently contains only `import` blocks and no other resources for the AWS provider. To generate configuration with `terraform plan -generate-config-out`, the docs say you must add
- You add an `import` block whose `to` argument is `aws_instance.web`, but your configuration contains no `resource "aws_instance" "web"` block yet. You would rather not write that block by hand. How ca
- An engineer wants the generated resources added into her existing `main.tf`, so she runs `terraform plan -generate-config-out=main.tf`, where `main.tf` already holds her provider and other resource bl
- A platform engineer has written several `import` blocks that each set a `to` address and an `id`, but none of the matching `resource` blocks exist in the configuration yet. She wants Terraform to writ
- An engineer has added several `import` blocks to a new configuration and now wants Terraform to auto-generate the corresponding `resource` HCL into a fresh file called `generated.tf` so she does not h
- Generated config is a starting point
Configuration produced by
-generate-config-outis a starting point that you should review and edit before applying, since generated blocks may include attributes that need adjustment to produce a valid plan.