With Terraform 1.5 and later, you can use the import
block to manage the import of resources directly in your configuration. This feature simplifies the process of importing existing infrastructure into Terraform state, eliminating the need for a separate CLI terraform import
command.
In this article, we explain the import block and how to use it to import different resources.
The Terraform import
block introduced in Terraform v1.5.0 provides a declarative approach for importing existing infrastructure resources into a Terraform state file. It allows resource imports to become an integral part of Terraform’s planning process — similar to other managed resources — rather than being treated as a direct state operation.
As a result, the import
block improves transparency and aligns resource imports with the core principles of infrastructure as code (IaC), enabling users to manage their infrastructure more effectively and predictably.
The syntax for an import
block in Terraform is as follows:
import {
to = <resource_address>
id = <resource_identifier>
}
to
: Specifies the resource address in your configuration where the imported resource will be mapped.id
: Defines the unique identifier of the existing resource in the provider’s API. Ensure that your Terraform provider is correctly configured to access the resource being imported.
Note that some resource types may have additional requirements or constraints for importing.
An import
block in Terraform lets you define resources directly in your configuration file, simplifying the management of existing infrastructure.
In contrast, when the terraform import
command is used without an import
block, it links an existing resource to the Terraform state but does not automatically generate the corresponding configuration in your code. You must manually add this configuration afterward. The import command is particularly useful for one-time imports or transitioning infrastructure into Terraform management.
Both methods require careful handling to ensure consistency between the Terraform state and the actual infrastructure. Import
blocks are generally better suited for ongoing resource management, whereas the standalone command works well for occasional imports.
Let’s suppose we have an existing AWS S3 bucket (my-existing-bucket
) that you want to manage with Terraform.
The resource
block specifies the S3 bucket (aws_s3_bucket.example
) and the bucket
attribute defines the name of the existing bucket:
resource "aws_s3_bucket" "example" {
bucket = "my-existing-bucket"
}
import {
to = aws_s3_bucket.example
id = "my-existing-bucket"
}
The import
block links the existing S3 bucket to the Terraform resource.
to
: Maps the imported resource to the address of theresource
block (aws_s3_bucket.example
)id
: Specifies the unique ID of the bucket (my-existing-bucket
).
When you run terraform plan
, Terraform reads the import
block, checks the state of the existing S3 bucket, and shows a preview of the changes it will make to the state file. Then, after we run terraform apply
, Terraform updates the state file to include the existing bucket, mapping it to the aws_s3_bucket.example
resource.
After running terraform apply
and successfully importing the resource, it is a best practice to remove the import
block. Keeping it won’t cause any harm, but removing it helps maintain a clean configuration and minimizes potential confusion during future state management.
Let’s consider another example: We have an existing EC2 instance with the ID i-1234567890abcdef0
and want to bring it under Terraform management.
We define the aws_instance
resource we want Terraform to manage in the resource
block. Make sure the attributes (e.g., ami
, instance_type
) match the existing instance’s configuration:
resource "aws_instance" "example" {
ami = "ami-0abcdef1234567890" # Replace with the actual AMI ID
instance_type = "t2.micro"
}
import {
to = aws_instance.example
id = "i-1234567890abcdef0"
}
In the import
block:
to
: Maps the resource in your configuration (aws_instance.example
) to the existing resource.id
: Specifies the unique ID of the EC2 instance you are importing.
Once you add the resource block and the import statement to your Terraform configuration file, run terraform plan
to preview the changes. Next, run terraform apply
to import the resource into Terraform’s state file.
After the import, Terraform will manage the existing EC2 instance, ensuring its configuration remains declarative.
In the next example, we will be importing an Azure Resource Group.
We have an existing Azure Resource Group named example-resource-group
in the East US
region, and we want to manage it with Terraform.
First, in the resource
block we define the azurerm_resource_group
resource that Terraform will manage:
resource "azurerm_resource_group" "example" {
name = "example-resource-group"
location = "East US"
}
import {
to = azurerm_resource_group.example
id = "/subscriptions/<subscription_id>/resourceGroups/example-resource-group"
}
The import block:
to
: Maps the resource in your configuration (azurerm_resource_group.example
) to the existing Azure resource.id
: Specifies the fully qualified Azure resource ID of the resource group. Remember to replace<subscription_id>
with your actual subscription ID.
Add the resource and the import block to your Terraform configuration file. Next, run the terraform plan
command to preview the changes and execute terraform apply
to apply the changes and import the resource into Terraform’s state file.
The Terraform import block is designed to be declarative and requires specific values known at plan time. Therefore, it cannot be used conditionally within your Terraform code.
The import block does not support dynamic expressions or variables for determining the import ID based on conditions. Attempts to use constructs like count or variables within the import block will result in errors, as Terraform does not allow such arguments in this context.
Spacelift is a wonderful tool if you need help managing your Terraform infrastructure, building more complex workflows based on Terraform, and managing AWS credentials per run, instead of using a static pair on your local machine.
Spacelift can optionally manage the Terraform state for you, offering a backend synchronized with the rest of the platform to maximize convenience and security. It also enables you to import your state during stack creation, which is very useful for engineers who are migrating their old configurations and states to Spacelift.
It supports Git workflows, policy as code, programmatic configuration, context sharing, drift detection, and many more great features right out of the box.
If you want to learn more about Spacelift, create a free account today or book a demo with one of our engineers.
The introduction of the import block in Terraform 1.5+ simplifies resource management by enabling the direct import and definition of resources within configuration files. It aligns with IaC principles by reducing complexity and making it easier to integrate existing infrastructure into Terraform configurations.
Note: New versions of Terraform are placed under the BUSL license, but everything created before version 1.5.x stays open-source. OpenTofu is an open-source version of Terraform that expands on Terraform’s existing concepts and offerings. It is a viable alternative to HashiCorp’s Terraform, being forked from Terraform version 1.5.6.
Manage Terraform Better with Spacelift
Build more complex workflows based on Terraform using policy as code, programmatic configuration, context sharing, drift detection, resource visualization and many more.