Import block

Import blocks are used when you want to import existing infrastructure component (or resources) into the Terraform statefile to bring them under Terraform management. Compared to using the Terraform import command, import blocks provide the ability to review the import operation before Terraform changes the statefile. The import block is available in Terraform v1.5.0 and later.
Once this resource is imported, Terraform will begin tracking it with the state file. You would then be able to manage this imported resource as you would any other, updating its attributes and destroying it if necessary.

Import block syntax

The syntax of a import block is as follows:
import {
    id = <source-resource-address-from-infrastructure>
    to = <target-resource-address-in-terraform-state>
}
resource resource_type <to> {
    # specify only known arguments
}
Here is the breakdown of syntax:
For instance, let's say you have an EC2 instance created manually in your infrastructure. To import that instance into your Terraform management (Terraform statefile), you would use the following import block:
import {
    id = "i-3456138463883"
    to = aws_instance.dummy_importing_resource
}
resource "aws_instance" "dummy_importing_resource" {
    name = "dev-server"
    instance_type = "t2.micro"
    # Other arguments if you known
}
In the above case, the instance i-3456138463883 will be imported into aws_instance.dummy_importing_resource resource and the attributes defined in the above resource block are the known arguments for this resource.
Once the import operation runs, Terraform will do the following:
Terraform will perform the following actions:
    # aws_instance.dummy_importing_resource will be imported
    resource "aws_instance" "dummy_importing_resource" {
        ami = "ami-abc123"
        instance_type = "t2.micro"
        name = "dev-server"
        tags {
            costcenter = "test"
        }
        credit_specification {
            cpu_credits = "unlimited"
        }
        network_interface {
            network_interface_id = "i-282223421"
            device_index = 0
        }
    }
Plan: 1 to import ,0 to add, 0 to change, 0 to destroy.
When you use terraform import <to> <id> to bring manually created infrastructure into your Terraform state file, you'll encounter the following limitations:
terraform import "aws_instance.dummy_importing_resource" i-3456138463883
aws_instance.dummy_importing_resource: Importing from ID "i-3456138463883"
aws_instance.dummy_importing_resource: Import prepared!

Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.
The imported resource will populate attributes in the Terraform state file as follows:
{
      "version" : 4
      "terraform_version" : 1.5.0
      "serial" : 8
      "lineage" : 60dd9c0a-caa1-de0e
      "outputs" : {}
      "resource" : {
          "mode" : "managed"
          "type" : "aws_instance"
          "name" : "dummy_importing_resource"
          "provider" : "provider[\"registry.terraform.io/hashicorp/aws\"]"
          "aws_security_group" : {
            "instances" : {
                "schema_version" : 0,
                "sensitive_attributes" : [],
                "attributes" : {
                      "id" = i-3456138463883
                      "ami" = "ami-abc123"
                      "instance_type" = "t2.micro"
                      "name" = "dev-server"
                      "tags" = [costcenter:"test"]
                      "credit_specification" = [cpu_credits: "unlimited"]
                      "network_interface" = [network_interface_id: "i-282223421", "device_index": 0]
                }
            }
        }
    }
}

Arguments in import block

The Following arguments are supported:

1. id

The id argument in the import block can be either literal string or an expression evaluating to a string. This provided value is an unique identifier of a resource you want to import into your Terraform statefile. The import ID needs to be known during the planning phase, meaning during terraform plan, for the whole thing to work. If the ID value, on the other hand, is known only after the resource has been applied (terraform apply), then the planning phase will fail with an error.

2. to

The to argument in the import block of Terraform is the destination address where the imported infrastructure will be kept in the Terraform statefile. If the specified address resource is not in the Terraform configuration, Terraform will return an error. You can prevent that by adding it yourself in the Terraform configuration or maybe let Terraform create it automatically with the flag -generate-config-out.

Meta Arguments of import Block

In Terraform, a meta-argument is a special kind of argument that can be used to customize the behavior of a resource block, Module block, and Data block.
Meta-arguments are the way to give you more control over how Terraform creates, updates, and destroys your infrastructure. Using them, you will be able to build complex and flexible configurations of the infrastructure.

Types of Meta Arguments Resource

Terraform provides several meta-arguments that can be utilized to customize the behavior of the import block. Import block supports the following two meta-arguments:

1. for_each

The for_each metaargument is a way to create multiple instances of a import block according to a collect of values. If a import block includes a for_each argument whose value should be either a map or a set of strings, then Terraform will create an instance for each member of that map or set.
Each instance is handled independently, with its own infrastructural object associated with it. This means each instance will be independently imported based on the changes you've made when applying your Terraform configuration.

Map Example

In the following example, we will use the for_each meta-argument with a map to import multiples AWS S3 buckets. We will then define a collected set of buckets operating under different names and regions, and Terraform will simply import the buckets for each of them.
local {
    buckets = {
        dev = "dev-bucket"
        staging = "stage-bucket"
        prod = "prod-bucket"
    }
}
import {
    for_each = tomap(locals.buckets)
    id = each.value
    to = aws_s3_bucket.s3[each.key]
}
resource "aws_s3_bucket" "buckets" {
    for_each = tomap(locals.buckets)
    name = each.value
    # Other arguments if you known
}
The tomap() here is a Terraform function that converts a list of key-value pairs into a map. The for_each meta-argument will step through the map, importing one instance of the aws_s3_bucket resource for each key-value pair. The each.key and each.value expressions are used to access the key and value of each pair, respectively.

Set Example

Here is an example where for_each is used on a set of strings to import many AWS RDS:
import {
    for_each = toset ([ "database-1", "database-2", "database-3" )]
    id = each.value
    to = aws_db_instance.database[each.key]
}
resource "aws_db_instance" "database" {
    for_each = toset ([ "database-1", "database-2", "database-3" )]
    allocated_storage = 10
    engine = "mysql"
    instance_class = "db.t2.micro"
    db_name = each.key
    username = "myuser"
    password = "mypassword"
}
Here, toset() is a Terraform function that takes a list of strings in and returns a set. The for_each meta-argument will iterate over that set and import one instance of the aws_db_instance resource for every string in that set. Finally, the each.key expression is used to access the string value of each item of that set using the db_names variable as the database name.

The provider Meta-Argument

The provider meta-argument in Terraform is special and is used to choose which provider configuration to use with a particular import block. It overrides Terraform's default behavior, which looks for a provider configuration with a matching to argument in import block.
By default, Terraform will automatically select a provider configuration based on the to argument in import block. For instance, if you declare the aws_instance.s3 in to argument, it will automatically select the default AWS provider configuration. However, in some cases, you may wish to use a different provider configuration.
The provider meta-argument is available to set explicitly which provider configuration is used for a import block. It takes the form of adding the provider name and alias (when using multiple configurations of the one provider type) to the block declaration.

Provider Syntax

The syntax for using the provider meta-argument is:
<PROVIDER>.<ALIAS>

Example

Suppose you have two configurations of provider for AWS Cloud:
provider "aws" {
    region = "us-east-1"
}
provider "aws" {
    alias = "europeregion"
    region = "eu-west-1"
}
Now you want to import an AWS instance, using the alternative "europeregion" configuration and not the default configuration. You can achieve that by adding the provider meta-argument to the import block declaration:
import {
    provider = aws.europeregion
    id = "i-3456138463883"
    to = aws_instance.importing_using_diff_provider
}
resource "aws_instance" "importing_using_diff_provider" {
    name = "server"
    instance_type = "t2.micro"
    # Other arguments if you known
}
Here, the provider meta-argument has been used to specify that the import block should use this "europeregion" configuration instead of using the default configuration. In other words, the EC2 instance will be imported from "eu-west-1" region as defined in "europeregion".

Import Block Behavior

Import Block in Terraform have a special property called idempotence. With idempotence, once you import a resource, when you run terraform plan again, it does not recreate the import action. The resource remains in your Terraform state, and Terraform will not try to import it again.
It only needs to import a resource once in Terraform. If you import the same resource again to the same address, Terraform will just do nothing, that is, it will be a "no-op". This is harmless and won't cause any issues.
When you have imported a resource, you can safely remove the import block from your configuration because it is no longer useful, or You may choose to leave the import block in your configuration as a record of where the resource came from, which is helpful for any future maintainers of this module.

Generating configuration

Before you actually import a resource, you should also have an already defined configuration for that resource in your Terraform code. Otherwise, Terraform will equally throw an error at planning, asking you to add the configuration of such a resource before it can successfully import it.
Resources can be configured manually if you know most of its arguments. However, when many resources are to be imported or you are importing one resource which is complex and you don't have the config at hand, then it is better to generate the configuration for it.
To create the resource configuration, run the following command:
terraform plan -generate-config-out=<filename>.tf
Make sure to provide a new file path for the generated configuration. Do not supply an existing file path because Terraform will error. If any of the resources targeted by an import block do not yet exist in your current configuration, Terraform will generate and write the configuration for those resources to the file specified. Once the configuration is generated into the file, you can make changes in that configuration to add, remove, or variablize the arguments, if you want.
# Generating Resource in file
import {
    id = "i-767267332573"
    to = aws_instance.generating_resource
}
# Importing infrastructure into defined Resource
import {
    id = "i-3456138463883"
    to = aws_instance.known_ec2
}
resource "aws_instance" "known_ec2" {
    name = "server"
    instance_type = "t2.micro"
    # Other arguments if you known
}
terraform plan -generate-config-out=generatedfile.tf
Terraform will perform the following actions:
aws_instance.generating_resource: Preparing import... [id=i-767267332573]
aws_instance.generating_resource: Refreshing state... [id=i-767267332573]
    # aws_instance.dummy_importing_resource will be imported
    # (config will be generated)
      resource "aws_instance" "generating_resource" {
          ami = "ami-abc456"
          instance_type = "t2.large"
          name = "prod-server"
          tags {
              appname = "hoster"
          }
          # Other arguments
      }

    # aws_instance.known_ec2 will be imported
      resource "aws_instance" "known_ec2" {
          ami = "ami-abc123"
          instance_type = "t2.small"
          name = "server"
          tags {
              appname = "hoster"
          }
          # Other arguments
      }
Plan: 2 to import, 0 to add, 0 to change, 0 to destroy.
Terraform has generated configuration and written it to generatedfile.tf. Please review the configuration and edit it as necessary before adding it to version control.
In this case, we do not know anything about arguments in the first scenario, so used Generating configuration by terraform method generates a file ./generatedfile.tf with the resource configuration. When we apply your Terraform configuration, the generating_resource (name given in to argument of that import block) resource generated in this file will be added to the statefile. In the second scenario, we know about the resource arguments, so we imported the infrastructure directly into the known_ec2 resource definition. Once you apply our Terraform configuration, the infrastructure being imported will be added into our state file.

Related Pages

Feedback

Was this page helpful?