HashiConf Global Join us for HashiConf Global October 4-6 in Los Angeles & online. Register Now
  • Overview
    • Enforce Policy as Code
    • Infrastructure as Code
    • Inject Secrets into Terraform
    • Integrate with Existing Workflows
    • Manage Kubernetes
    • Manage Virtual Machine Images
    • Multi-Cloud Deployment
    • Network Infrastructure Automation
    • Terraform CLI
    • Terraform Cloud
    • Terraform Enterprise
  • Registry
  • Tutorials
    • About the Docs
    • Intro to Terraform
    • Configuration Language
    • Terraform CLI
    • Terraform Cloud
    • Terraform Enterprise
    • Provider Use
    • Plugin Development
    • Registry Publishing
    • Integration Program
    • Terraform Tools
    • CDK for Terraform
    • Glossary
  • Community
GitHub
Download
Try Terraform Cloud
    • v0.11.x (latest)
    • v0.10.x
    • v0.9.x
    • v0.8.x
    • v0.7.x

    Framework

  • Overview
  • Tutorial: Implement Create and Read
  • Provider Servers
  • Providers
    • Overview
    • Import
    • Plan Modification
    • State Upgrade
  • Data Sources
  • Schemas
  • Paths
  • Path Expressions
  • Attribute Types
  • Accessing State, Config, and Plan
  • Writing State
  • Returning Errors and Warnings
  • Validation
  • Acceptance Tests
  • Debugging
  • Other Plugin Docs

  • Plugin Development
  • SDKv2
  • Logging
  • Combining and Translating
Type '/' to Search

»Resource Import

Practitioners can use the terraform import command to let Terraform begin managing existing infrastructure resources. Resources can implement the ImportState method, which must either specify enough Terraform state for the Read method to refresh resource.Resource or return an error.

»Single Attribute

When the Read method requires a single attribute to refresh, use the resource.ImportStatePassthroughID function to write the import identifier argument for terraform import.

In the following example, the terraform import command passes the import identifier to the id attribute in Terraform state.

func (r exampleResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
    resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}
func (r exampleResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
    resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}

»Multiple Attributes

When the Read method requires multiple attributes to refresh, you must write custom logic in the ImportState method. Specifically, the implementation must:

  1. Use the import identifier from the resource.ImportStateRequest.
  2. Perform the custom logic.
  3. Set state data in the resource.ImportStateResponse.

For example, if the provider.ResourceType implementation has the following GetSchema method:

func (t exampleResourceType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
    return tfsdk.Schema{
        Attributes: map[string]tfsdk.Attribute{
            "attr_one": {
                Type:     types.StringType,
                Required: true,
            },
            "attr_two": {
                Type:     types.StringType,
                Required: true,
            },
            // ... potentially other Attributes ...
        },
    }, nil
}
func (t exampleResourceType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
    return tfsdk.Schema{
        Attributes: map[string]tfsdk.Attribute{
            "attr_one": {
                Type:     types.StringType,
                Required: true,
            },
            "attr_two": {
                Type:     types.StringType,
                Required: true,
            },
            // ... potentially other Attributes ...
        },
    }, nil
}

Along with a resource.Resource implementation with the following Read method:

func (r exampleResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
    var attrOne, attrTwo string

    resp.Diagnostics.Append(req.State.GetAttribute(ctx, path.Root("attr_one"), &attrOne)...)
    resp.Diagnostics.Append(req.State.GetAttribute(ctx, path.Root("attr_two"), &attrTwo)...)

    if resp.Diagnostics.HasError() {
        return
    }

    // API call using attrOne and attrTwo
}
func (r exampleResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
    var attrOne, attrTwo string

    resp.Diagnostics.Append(req.State.GetAttribute(ctx, path.Root("attr_one"), &attrOne)...)
    resp.Diagnostics.Append(req.State.GetAttribute(ctx, path.Root("attr_two"), &attrTwo)...)

    if resp.Diagnostics.HasError() {
        return
    }

    // API call using attrOne and attrTwo
}

The terraform import command will need to accept both attribute values as a single import identifier string. A typical convention is to use a separator character, such as a comma (,), between the values. The ImportState method will then need to parse the import identifier string into the two separate values and save them appropriately into the Terraform state.

You could define the ImportState method using a comma-separated value as follows:

func (r exampleResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
    idParts := strings.Split(req.ID, ",")

    if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" {
        resp.Diagnostics.AddError(
            "Unexpected Import Identifier",
            fmt.Sprintf("Expected import identifier with format: attr_one,attr_two. Got: %q", req.ID),
        )
        return
    }

    resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("attr_one"), idParts[0])...)
    resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("attr_two"), idParts[1])...)
}
func (r exampleResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
    idParts := strings.Split(req.ID, ",")

    if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" {
        resp.Diagnostics.AddError(
            "Unexpected Import Identifier",
            fmt.Sprintf("Expected import identifier with format: attr_one,attr_two. Got: %q", req.ID),
        )
        return
    }

    resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("attr_one"), idParts[0])...)
    resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("attr_two"), idParts[1])...)
}

»Not Implemented

If the resource does not support terraform import, skip the ImportState method implementation.

When a practitioner runs terraform import, Terraform CLI will return:

$ terraform import example_resource.example some-identifier
example_resource.example: Importing from ID "some-identifier"...
╷
│ Error: Resource Import Not Implemented
│ 
│ This resource does not support import. Please contact the provider developer for additional information.
╵
$ terraform import example_resource.example some-identifier
example_resource.example: Importing from ID "some-identifier"...
╷
│ Error: Resource Import Not Implemented
│ 
│ This resource does not support import. Please contact the provider developer for additional information.
╵
github logoEdit this page
  • Overview
  • Docs
  • Extend
  • Privacy
  • Security
  • Press Kit
  • Consent Manager