Zendoric
← Back to the day · November 10, 2026

How to import existing resources into OpenTofu: CLI vs. import blocks (Spacelift tutorial)

🕒 Published on Zendoric: November 10, 2026 · 02:47

✨ AI-generated · how it's made

The article, published on the Spacelift blog, is a hands-on tutorial on how to bring into OpenTofu infrastructure that already exists outside your infrastructure as code (IaC) process.

The article, published on the Spacelift blog, is a hands-on tutorial on how to bring infrastructure that already exists outside your infrastructure as code (IaC) process into OpenTofu. Note to readers: the text received is truncated midway through the section on automatic configuration generation with -generate-config-out, so this summary covers only what appears in that portion of the content and not the final sections (common errors, best practices, managing at scale with Spacelift and conclusions).

The starting premise is that almost every environment has resources created by hand, with custom scripts or with other tools. Importing means linking a real provider resource to an OpenTofu resource: if the operation succeeds, the state file stores the object's attributes and its lifecycle is then managed from OpenTofu like any other resource. The article lists the most common use cases: infrastructure created manually or with scripts, migrations from tools such as CloudFormation, Pulumi, Crossplane or Azure Bicep, state recovery after accidental deletion or corruption, splitting a large state into smaller configurations, and emergency changes made by hand.

Two mechanisms are described. The first is the tofu import CLI command, inherited from Terraform, which takes a resource address and a provider ID and writes to the state immediately, with no plan, preview or approval. The second is the import block, which is written into the configuration, evaluated during tofu plan (showing exactly what will happen) and executed during tofu apply. According to the article, the import block has existed since OpenTofu 1.6, gained for_each in 1.7 and the identity argument in 1.12. The latter is mainly useful for resources whose identifier is a composite key.

As prerequisites, the author mentions using an OpenTofu version that supports the required capabilities, having the provider configured, a remote backend in production environments and read permissions on the resources, as well as checking that the resource type supports import. To find the correct ID, the author recommends always checking the "Import" section at the bottom of the resource's page in the OpenTofu registry. Some resources are imported with a simple ID, such as an EC2 instance, while others require a composite key, such as aws_security_group_rule, which combines the security group ID, rule type, protocol, ports and source joined by underscores.

In method 1 (CLI), the syntax is tofu import [options] ADDR ID. The address can point to root resources, resources inside modules or specific instances with count or for_each, for example module.networking.aws_vpc.main, aws_vpc.main[0] or aws_vpc.main["london"], with the note that on some operating systems double quotes must be escaped. The example creates an S3 bucket with the AWS CLI, declares an aws_s3_bucket resource with the same name, runs tofu init and imports using the bucket name as the ID. Afterwards, tofu state list shows the resource and tofu plan reports no changes. Useful options cited include -config, -var and -var-file, -no-color (handy in CI logs) and -input=false to avoid interactive prompts.

The author lists the limitations of the CLI route, which is why he recommends the import block: it imports only one object per invocation (50 resources means 50 runs), there is no preview and it modifies state directly (if you get the address wrong, you have to remove the resource from state and start over), it does not generate configuration, it leaves no record in the code that something was imported, and it fits poorly into CI/CD pipelines because it requires adding an import step and removing it afterwards.

In method 2, the import block uses the to argument (the target resource address) and either id or identity. The block is only active as long as OpenTofu is not already tracking an object at that address, so it can be kept as a historical record or deleted. It is recommended to place it in a dedicated imports.tf file or next to the resource. The id argument is the classic approach (a string in the format the provider expects), while identity, available since 1.12, uses an object whose attributes come from the resource type's identity schema. The provider meta-argument can also be used when there are multiple aliased providers, to determine which credentials and region are used to look up and import the resource.

In the step-by-step example, after init, tofu plan shows "Plan: 1 to import, 0 to add, 0 to change, 0 to destroy" and details the bucket's attributes; tofu apply ends with "1 imported". Running apply again without removing the block produces no changes. To import multiple resources, the article creates a second bucket and combines a variable holding the list of names, an aws_s3_bucket resource with for_each and an import block with for_each that uses each.value in both the to address and identity. The result is "2 imported".

The advantages summarized for import blocks are: there is a history of what was imported and what was created with OpenTofu, multiple resources can be imported with a single block via for_each, there is a preview with tofu plan before anything is mutated (making it CI-friendly), and configuration can be generated automatically.

Finally, the text introduces the tofu plan -generate-config-out=generated_resources.tf option, which writes the resource configuration for you based on an import block. The article warns that the feature is still experimental and does not work with resources that use for_each or count. The description of the output is cut off at this point. Overall, the core message is clear: use import blocks instead of the CLI command, check the import ID in the registry and always review the plan before applying.

🔗 Related on Zendoric

Sources & references