Terraform
Migrating providers
Providers are Terraform plugins that define resources and data sources for practitioners to use. You serve your providers with a provider server so they can interact with Terraform. The provider schema defines the allowed attributes and other configuration data about your provider.
This page explains how to migrate a provider server, definition, and schema from SDKv2 to the plugin framework. Refer to the Migrating schema page in this migration guide to learn how to migrate your provider's schema to the framework.
Background
Terraform connects to your provider over RPC. The provider server connects to
Terraform and handles RPC calls between Terraform and your provider code. When
you migrate your provider from SDKv2 to Terraform, you must update your provider
server, provider definition, and provider schema. When you migrate using the
terraform-plugin-mux module, your provider server will serve both the SDKv2
and framework versions of your provider. Once migration is complete, remove the
SDKv2 versions of your provider server, definition, and schema.
Serving the provider
You must update your provider's main.go file to serve your framework provider.
Refer to Provider Servers in the
framework documentation for details about framework provider servers.
Migrate over multiple release cycles
You can use the terraform-plugin-mux module to help you iteratively migrate
individual resources and data sources to the framework across multiple release
cycles. The module multiplexes, or muxes, data using SDKv2 and the framework
concurrently. Refer to Migration using a mux
server for more information.
Migrate in a single release cycle
If you are migrating your provider in a single release cycle, update your
provider's main() function to serve the framework provider instead of the
SDKv2 version.
In SDKv2, the provider package's main function serves the provider by calling
plugin.Serve.
The following code shows a basic implementation for serving an SDKv2 provider.
SDKv2
func main() {
    plugin.Serve(
        &plugin.ServeOpts{
            ProviderFunc: provider.New,
            ProviderAddr: "registry.terraform.io/<namespace>/<provider_name>",
        },
    )
}
In the framework, serve your provider by calling providerserver.Serve in your
provider package's main function. Refer to Provider
Servers in the framework
documentation for details about provider servers.
The following code shows an equivalent implementation for serving a provider in the framework.
Framework
func main() {
    err := providerserver.Serve(
        context.Background(),
        provider.New,
        providerserver.ServeOpts{
            Address: "registry.terraform.io/<namespace>/<provider_name>",
        },
    )
    if err != nil {
        log.Fatal(err)
    }
}
Provider definition
Providers built with SDKv2 use a schema.Provider struct to define their
behavior, while framework providers use a type that you define that implements
the provider.Provider interface. Refer to
Providers in the framework
documentation for details about framework provider definitions.
When migrating using a mux provider server, you will implement both the SDKv2 and framework versions of your provider definition during the migration. Once you have completed the migration, remove the SDKv2 provider definition and related mux server code from your provider server.
The
ProviderFunc
field on plugin.ServeOpts requires a pointer to schema.Provider to access
your provider's schema. This is typically satisfied by calling a function that
returns a pointer to schema.Provider.
The ResourcesMap and DataSourcesMap fields each contain a map of strings to
functions that each return a pointer to a schema.Resource struct for the given
resource or data source.
The following example shows a basic implementation of an SDKv2 provider.
SDKv2
func New() *schema.Provider {
    return &schema.Provider{
        Schema:         map[string]*schema.Schema{},
        ConfigureContextFunc:   configureContextFunc(),
        ResourcesMap:   map[string]*schema.Resource{
            "resource_example": resourceExample(),
        },
        DataSourcesMap: map[string]*schema.Resource{
            "dataSource_example": dataSourceExample(),
        },
        /* ... */
    }
}
In the framework, the second argument to your provider.Serve function requires
a function that returns a type satisfying the provider.Provider interface.
The following code shows a typical implementation. In this implementation, the
Resources method returns a slice of functions that return types that implement
the resource.Resource interface. The DataSources method returns a slice of
functions that return types that implement the datasource.DataSource
interface. Refer to the
Resources and Data
Sources pages in this guide
to implement these functions for your provider.
Framework
type exampleCloudProvider struct {
}
func New() provider.Provider {
    return &exampleCloudProvider{}
}
func (p *exampleCloudProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
    resp.TypeName = "examplecloud"
}
func (p *exampleCloudProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) {
    resp.Schema = schema.Schema{}
}
func (p *exampleCloudProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
}
func (p *exampleCloudProvider) Resources(ctx context.Context) []func() resource.Resource {
    return []func() resource.Resource {
        func() resource.Resource {
            return resourceExample{}
        },
    }
}
func (p *exampleCloudProvider) DataSources(ctx context.Context) []func() datasource.DataSource {
    return []func() datasource.DataSource {
        func() datasource.DataSource {
            return dataSourceExample{}
        },
    }
}
Migration notes
Remember the following differences between SDKv2 and the framework when you migrate your provider definition.
- In SDKv2, your provider's Newfunction returns a pointer to aschema.Providerstruct. In the framework,Newreturns a type that you define which satisfies theprovider.Providerinterface.
- In SDKv2, Schemais a field onschema.Providerthat containsmap[string]*schema.Schema, which maps attribute names toschema.Schemastructs. In the framework,Schemais a method you define on your provider that returns your provider'sschema.Schemastruct.
- In SDKv2, ConfigureContextFuncis a field onschema.Providercontaining a function that configures the provider. In the framework,Configureis a function you define on your provider that configures your provider.
- In SDKv2, ResourcesMapis a field onschema.Providercontainingmap[string]*schema.Resource, which maps resource names toschema.Resourcestructs. In the framework,Resourcesis a method you define on your provider that returns[]func() resource.Resource, a slice of resource types that you define which satisfy theresource.Resourceinterface.
- In SDKv2, DataSourcesMapis a field onschema.Providercontainingmap[string]*schema.Resource, which maps data source names toschema.Resourcestructs. SDKv2 data sources and resources both useschema.Resource. In the framework,DataSourcesis a method you define on your provider that returns[]func() datasource.DataSource, a slice of data source types that you define which satisfy thedatasource.DataSourceinterface.
Example
The following example shows how to set up a provider schema, configuration, resources, and data sources using SDKv2.
SDKv2
func New() (*schema.Provider, error) {
    return &schema.Provider{
        Schema: map[string]*schema.Schema{
            "attribute": {
                /* ... */
            },
        },
        ConfigureContextFunc: configureProvider,
        ResourcesMap: map[string]*schema.Resource{
            "exampleResource": exampleResource(),
            /* ... */
        },
        DataSourcesMap: map[string]*schema.Resource{
            "exampleDataSource": exampleDataSource(),
            /* ... */
        },
    }, nil
}
The following shows the same section of provider code after the migration.
Framework
var _ provider.Provider = (*exampleProvider)(nil)
func New() provider.Provider {
    return &exampleProvider{}
}
func (p *exampleProvider) Resources(_ context.Context) []func() resource.Resource {
    return []func() resource.Resource{
        func() resource.Resource {
            return &exampleResource{}
        },
        /* ... */
    }
}
func (p *exampleProvider) DataSources(_ context.Context) []func() datasource.DataSource {
    return []func() datasource.DataSource{
        func() datasource.DataSource {
            return &exampleDataSource{}
        },
        /* ... */
    }
}
func (p *exampleProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
    resp.Schema = schema.Schema{
        Attributes: map[string]schema.Attribute{
            "attribute": schema.SingleNestedBlock{
                /* ... */
            },
        },
    }
}
func (p *exampleProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
    resp.TypeName = "example"
}
func (p *exampleProvider) Configure(_ context.Context, _ provider.ConfigureRequest, resp *provider.ConfigureResponse) {
    /* ... */
}
Provider schema
A provider schema defines the attributes and behaviors of the provider. For example, a provider that connects to a third-party API may define attributes for the base URL or a required authentication token.
When you use a muxed provider server to migrate from SDKv2 to the framework, the SDKv2 version of your provider definition uses an SDKv2 provider schema, and your framework provider definition uses a framework provider schema. Once you have completed the migration, remove the SDKv2 provider schema along with the provider definition and related mux code from your provider server.
In SDKv2, you implement a provider schema by populating the Schema field on
the schema.Provider struct. The Schema field contains a
map[string]*schema.Schema. Each map entry represents the name of the attribute
and pointer to a schema.Schema struct that defines that attribute's behavior.
In the framework, the Schema method returns the provider schema. The Schema
method is part of the
provider.Provider
interface that your provider must implement. Schema returns a struct
containing fields for Attributes and Blocks. These Attributes and Blocks
contain map[string]schema.Attribute and map[string]schema.Block,
respectively. Refer to Providers -
Schema in the framework
documentation for details about framework provider schema.
The following example defines the provider schema in the Schema field within
the schema.Provider struct.
SDKv2
func New() *schema.Provider {
    return &schema.Provider{
        Schema: map[string]*schema.Schema{
            /* ... */
        },
The following code shows the Schema method, which returns the provider schema.
SDKv2
func (p *ExampleCloudProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) {
    resp.Schema = schema.Schema{
        /* ... */
    }
}
Refer to the Migrating schema page in this migration guide to learn how to migrate schema to the framework.
Migration notes
- In SDKv2, schema.Schemais a struct that defines attributes and behaviors, such asTypeorOptional. In the frameworkschema.Schemais a struct that includes attributes and blocks.
Examples
Refer to the following examples when you migrate your provider.
Nested blocks and attributes
This example shows how to use a nested block and a nested attribute for the SDKv2 and framework examples, respectively. Refer to the Blocks with Computed Fields page in this guide for more details.
The following example shows the configuration of the example_attribute
attribute for the provider's example_block configuration block in SDKv2.
SDKv2
Schema: map[string]*schema.Schema{
    "example_block": {
        Type:     schema.TypeList,
        Optional: true,
        MaxItems: 1,
        Elem: &schema.Resource{
            Schema: map[string]*schema.Schema{
                "example_attribute": {
                    Type:             schema.TypeString,
                    Optional:         true,
                    ValidateDiagFunc: validation.ToDiagFunc(validation.IsURLWithScheme(SupportedProxySchemesStr())),
                    ConflictsWith:    []string{"example_block.0.another_attribute"},
                },
                /* ... */
The following shows the same section of provider code after the migration.
This code implements the example_attribute attribute for the example_Block
block with the framework.
Framework
func (p *exampleProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
    resp.Schema = schema.Schema{
        /*...*/
        Blocks: map[string]schema.Block{
            "example_block": schema.ListNestedBlock{
                NestedObject: schema.NestedBlockObject{
            Attributes: map[string]schema.Attribute{
                "example_attribute": schema.StringAttribute{
                Optional: true,
                Validators: []validator.String{
                    attribute_validator.UrlWithScheme(supportedProxySchemesStr()...),
                    stringvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("another_attribute")),
                },
            },
        },
        Validators: []validator.List{
                listvalidator.SizeAtMost(1),
        },