- The OpenTofu Language
- Import
Import
While we do not expect to make backwards-incompatible changes to syntax, the -generate-config-out flag and how OpenTofu processes imports during the plan stage and generates configuration may change in future releases.
Use the import block to import existing infrastructure objects into OpenTofu, bringing them under OpenTofu's management. Unlike the tofu import command, configuration-driven import using import blocks is predictable, works with CICD pipelines, and lets you preview an import operation before modifying state.
Once imported, OpenTofu tracks the object as a resource instance in your state file. You can then manage the imported object like any other, updating its attributes and destroying it as part of a standard resource lifecycle.
The import block represents that OpenTofu imported the object and did not create it. After importing, you can optionally remove import blocks from your configuration or leave them as a record of the object's origin.
Syntax​
You can add an import block to any OpenTofu configuration file. A common pattern is to create an imports.tf file, or to place each import block beside the resource block it imports into.
import {
identity = {
id = "i-abcd1234"
}
to = aws_instance.example
}
resource "aws_instance" "example" {
name = "hashi"
# (other resource arguments...)
}
The above import block defines an import of the AWS instance with the ID "i-abcd1234" into the aws_instance.example resource in the root module.
The import block has the following arguments:
- Either
identityorid- To specify which remote object to import. to- The resource instance address that OpenTofu will use to track this object in OpenTofu state.provider(optional) - The provider instance to use for importing, as with The Resource provider Meta-Argument.for_each(optional) - Import several objects as multiple instances of the same resource by iterating over a map or a set. See Importing multiple resources below.
If you do not set the provider argument, OpenTofu attempts to import from the default provider.
Specifying what to import​
The identity and id arguments offer two different ways to specify which remote object you intend to import. These arguments are mutually-exclusive.
The identity argument is the modern approach which specifies the remote object by specifying one or more attributes whose names and types vary depending on the resource type's identity schema. For example, importing into an aws_instance resource instance requires an object with a single id attribute:
import {
identity = {
id = "i-abcd1234"
}
to = aws_instance.example
}
Not all resource types have been updated to support identity yet. For older resource types you must use the top-level id argument instead and specify the remote object using a single string in whatever form the provider is expecting. For example, aws_instance expects the instance ID directly when using this legacy approach:
import {
id = "i-abcd1234"
to = aws_instance.example
}
Refer to the documentation for the resource type you are importing into to learn whether that resource type has an identity schema to use with identity, or if it still requires you to use the legacy id argument.
Plan and apply an import​
OpenTofu processes the import block during the plan stage. Once a plan is approved, OpenTofu imports the object into its state during the subsequent apply stage.
To import an object using import blocks, you must:
- Write
importblocks describing the relationship between the remote objects and the resource instance addresses OpenTofu should use to track them. - Add the corresponding
resourceblocks to your configuration , or generate initial configuration automatically. - Run
tofu planto review how OpenTofu will import the objects. - Apply the plan to import the objects and update your OpenTofu state.
An import block is active only if OpenTofu is not already tracking an object with the address given in to. After importing is successful, an import block becomes inert and you can optionally remove it from your configuration or retain it as a historical record for future maintainers. For more information on maintaining configurations over time, refer to Refactoring
Resource configuration​
Before importing, you must add a resource block for every object (or collection of related objects) you want OpenTofu to import. Otherwise, OpenTofu raises an error during planning, insisting you add resource configuration before it can successfully import. You can create resource configuration manually or generate it using OpenTofu.
We recommend writing a resource block if you know what most of the resource's arguments will be. For example, your configuration may already contain a similar resource whose configuration you can copy and modify.
We recommend generating configuration when importing multiple objects or a single complex object that you do not already have the configuration for.
Add a resource block​
Add a resource block for the resource to import into. The to argument in the import block must refer to that resource.
import {
to = aws_instance.example
id = "i-abcd1234"
}
resource "aws_instance" "example" {
name = "renderer"
}
Generate configuration​
OpenTofu can generate resource blocks for resources that are not already declared in your configuration.
For more details, refer to Generating Configuration.
Examples​
The following example demonstrates how to import into a module.
import {
to = module.instances.aws_instance.example
id = "i-abcd1234"
}
The below example shows how to import a resource that includes count.
import {
to = aws_instance.example[0]
id = "i-abcd1234"
}
The below example shows how to import a resource that includes for_each.
import {
to = aws_instance.example["foo"]
id = "i-abcd1234"
}
Finally, the below example demonstrates how to import from a custom resource provider.
provider "aws" {
alias = "europe"
region = "eu-west-1"
}
import {
provider = aws.europe
to = aws_instance.example["foo"]
id = "i-abcd1234"
}
Importing multiple objects​
You can import multiple resources instances with one import block by using a for_each expression. This expression accepts a set, a tuple or a map and provides the each.key and each.value variables to access the individual elements.
In the example below, you can specify a list of server IDs to be imported. If you specify an empty list, the random_id resource will generate all IDs randomly. If you specify some IDs, the import block will import the specified IDs and the resource will randomly generate the rest. Note, the random_id resource requires the IDs to be in base64 format.
variable "server_ids" {
type = list(string)
}
resource "random_id" "test_id" {
byte_length = 8
count = 2
}
import {
to = random_id.test_id[tonumber(each.key)]
id = each.value
for_each = {
for idx, item in var.server_ids: idx => item
}
}
output "id" {
value = random_id.test_id.*.b64_url
}
Generating configuration is currently not possible when using for_each on import blocks.