Terraform
- Plugin Framework
- v1.16.x (latest)
- No versions of this document exist before v1.15.x. Click below to redirect to the version homepage.
- v1.15.x
- v1.14.x
- v1.13.x
- v1.12.x
- v1.11.x
- v1.10.x
- v1.9.x
- v1.8.x
- v1.7.x
- v1.6.x
- v1.5.x
- v1.4.x
- v1.3.x
- v1.2.x
- v1.1.x
- v1.0.x
- v0.17.x
- v0.16.x
- v0.15.x
- v0.14.x
- v0.13.x
- v0.11.x
- v0.10.x
- v0.9.x
- v0.8.x
- v0.7.x
Provider
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.
This page explains how to migrate a provider server, definition, and schema from SDKv2 to the plugin Framework.
Serving the Provider
You must update your provider's main.go file to serve Framework providers. Refer to Provider Servers in the Framework documentation for details.
SDKv2
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.
func main() {
    plugin.Serve(
        &plugin.ServeOpts{
            ProviderFunc: provider.New,
            ProviderAddr: "registry.terraform.io/<namespace>/<provider_name>",
        },
    )
}
Framework
In the Framework, you serve your provider by calling providerserver.Serve in your provider package's main function.
Refer to Provider Servers in the Framework documentation for details.
The following code shows an equivalent implementation for serving a provider in the 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)
    }
}
Muxing
Muxing lets you use two versions of the same provider concurrently, with each serving different resources or data sources. Refer to the Combining and Translating documentation for full details about muxing configuration. Use muxing when you want to release a version of your provider with only some of the resources and data sources migrated to the Framework. You may want to do this if your provider manages a large number of resources and data sources.
The following example shows how to set up muxing for a provider that uses protocol version 5 to maintain compatibility
with Terraform >= 0.12.0. The example also shows how to use the debug flag to optionally run the provider in debug
mode.
func main() {
    ctx := context.Background()
    var debug bool
    flag.BoolVar(&debug, "debug", false, "set to true to run the provider with support for debuggers like delve")
    flag.Parse()
    providers := []func() tfprotov5.ProviderServer{
        providerserver.NewProtocol5(provider.New()),
        provider.Provider().GRPCProvider,
    }
    muxServer, err := tf5muxserver.NewMuxServer(ctx, providers...)
    if err != nil {
        log.Fatal(err)
    }
    var serveOpts []tf5server.ServeOpt
    if debug {
        serveOpts = append(serveOpts, tf5server.WithManagedDebug())
    }
    err = tf5server.Serve(
        "registry.terraform.io/<namespace>/<provider_name>",
        muxServer.ProviderServer,
        serveOpts...,
    )
    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 implements the provider.Provider interface, which you must define.  Refer to Providers in the Framework documentation for details.
SDKv2
The ProviderFunc field on
plugin.ServeOpts requires a pointer to schema.Provider. 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.
The following example shows a basic implementation of an SDKv2 provider.
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(),
        },
        /* ... */
    }
}
Framework
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 GetResources function returns a map
from resource names (strings) to types that implement the provider.ResourceType interface. The GetDataSources
function returns a map from data source names (strings) to types that implement the provider.DataSourceType interface.
Refer to the Resources and
Data Sources pages in this guide to implement these functions for your
provider.
type provider struct {
}
func New() provider.Provider {
    return &provider{}
}
func (p *provider) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
    return tfsdk.Schema{}, nil
}
func (p *provider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
}
func (p *provider) GetResources(ctx context.Context) (map[string]provider.ResourceType, diag.Diagnostics) {
    return map[string]provider.ResourceType{
        "resource_example": resourceTypeExample{},
    }, nil
}
func (p *provider) GetDataSources(ctx context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) {
    return map[string]provider.DataSourceType{
        "data_source_example": dataSourceTypeExample{},
    }, nil
}
Migration Notes
Remember the following differences between SDKv2 and the Framework when completing the migration.
- In SDKv2, your provider's Newfunction returns 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,GetSchemais a function you define on your provider'sprovider.Providerinterface that returns your provider'stfsdk.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,GetResourcesis a function you define on your provider that returnsmap[string]provider.ResourceType, which maps resource names to types that you define, which satisfy theprovider.ResourceTypeinterface.
- In SDKv2, DataSourcesMapis a field onschema.Providercontainingmap[string]*schema.Resource, which maps data source names toschema.Resourcestructs (data sources and resources both useschema.Resource). In the Framework,GetDataSourcesis a function you define on your provider that returnsmap[string]provider.DataSourceType, which maps data source names to types that you define, which satisfy theprovider.DataSourceTypeinterface.
Example
The following examples show how to migrate portions of the tls provider.
For a complete example, clone the
terraform-provider-tls repository and compare provider.go in
v3.4.0
with v4.0.1.
SDKv2
The following example shows how to set up a provider schema, configuration, resources, and data sources using SDKv2.
func New() (*schema.Provider, error) {
    return &schema.Provider{
        Schema: map[string]*schema.Schema{
            "proxy": {
                /* ... */
            },
        },
        ConfigureContextFunc: configureProvider,
        ResourcesMap: map[string]*schema.Resource{
            "tls_private_key": resourcePrivateKey(),
            /* ... */
        },
        DataSourcesMap: map[string]*schema.Resource{
            "tls_public_key": dataSourcePublicKey(),
            /* ... */
        },
    }, nil
}
Framework
The following shows the same section of provider code after the migration.
var _ provider.Provider = (*provider)(nil)
func New() provider.Provider {
    return &provider{}
}
func (p *provider) GetResources(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) {
    return map[string]provider.ResourceType{
        "tls_private_key":         &privateKeyResourceType{},
        /* ... */
    }, nil
}
func (p *provider) GetDataSources(_ context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) {
    return map[string]provider.DataSourceType{
        "tls_public_key":  &publicKeyDataSourceType{},
        /* ... */
    }, nil
}
func (p *provider) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) {
    return tfsdk.Schema{
        Attributes: map[string]tfsdk.Attribute{
            "proxy": {
                /* ... */
            },
        },
    }, nil
}
func (p *provider) Configure(ctx context.Context, req provider.ConfigureRequest, res *provider.ConfigureResponse) {
    /* ... */
}
Provider Schema
A provider schema defines the attributes and behaviors of the provider itself. For example, a provider that connects to a third-party API may define attributes for the base URL or a required authentication token.
SDKv2
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.
The following example defines the provider schema in the Schema field within the schema.Provider struct.
func New() *schema.Provider {
    return &schema.Provider{
        Schema: map[string]*schema.Schema{
            /* ... */
        },
Framework
In the Framework, the GetSchema function returns the provider schema. The GetSchema function is part of the
provider.Provider interface that your provider must implement. GetSchema returns a struct containing fields for
Attributes and Blocks. These Attributes and Blocks contain map[string]tfsdk.Attribute and
map[string]tfsdk.Block, respectively. Refer to Providers - GetSchema in the
Framework documentation for details.
The following code shows the GetSchema function, which returns the provider schema.
func (p *provider) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
    return tfsdk.Schema{
        /* ... */
    }, nil
}
Refer to the Attributes and Blocks pages in this migration guide to learn how to migrate those fields to the Framework.
Migration Notes
Remember the following differences between SDKv2 and the Framework when completing the migration.
- In SDKv2, schema.Schemais a struct that defines attributes and behaviors (e.g.,Type,Optional). In the Frameworktfsdk.Schemais a struct that includestfsdk.Attributes, which are structs that define attributes and behaviors (e.g.,Type,Optional).
Example
The following examples show how to migrate portions of the tls provider.
For a complete example, clone the
terraform-provider-tls repository and compare provider.go in
v3.4.0
with v4.0.1.
This example also 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.
SDKv2
The following example from the provider.go file shows the configuration of the url attribute for the  provider'sproxy configuration block.
Schema: map[string]*schema.Schema{
    "proxy": {
        Type:     schema.TypeList,
        Optional: true,
        MaxItems: 1,
        Elem: &schema.Resource{
            Schema: map[string]*schema.Schema{
                "url": {
                    Type:             schema.TypeString,
                    Optional:         true,
                    ValidateDiagFunc: validation.ToDiagFunc(validation.IsURLWithScheme(SupportedProxySchemesStr())),
                    ConflictsWith:    []string{"proxy.0.from_env"},
                    Description: "URL used to connect to the Proxy. " +
                        fmt.Sprintf("Accepted schemes are: `%s`. ", strings.Join(SupportedProxySchemesStr(), "`, `")),
                },
                /* ... */
Framework
The following shows the same section of provider code after the migration.
This code implements the url attribute for the proxy block with the Framework.
func (p *provider) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) {
    return tfsdk.Schema{
        Attributes: map[string]tfsdk.Attribute{
            "proxy": {
                Optional: true,
                Attributes: tfsdk.SingleNestedAttributes(map[string]tfsdk.Attribute{
                    "url": {
                        Type:     types.StringType,
                        Optional: true,
                        Validators: []tfsdk.AttributeValidator{
                            attribute_validator.UrlWithScheme(supportedProxySchemesStr()...),
                            schemavalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("from_env")),
                        },
                        MarkdownDescription: "URL used to connect to the Proxy. " +
                            fmt.Sprintf("Accepted schemes are: `%s`. ", strings.Join(supportedProxySchemesStr(), "`, `")),
                    },