Terraform
Combining Protocol Version 6 Providers
The tf6muxserver package enables combining any number of protocol version 6 provider servers into a single server.
Use this package to:
- Support multiple development teams across separate codebases.
- Support multiple provider SDK implementations. For example, you could upgrade an existing terraform-plugin-sdk/v2 provider to protocol version 6 and then combine it with one or more providers built with terraform-plugin-framework.
Compatibility
Protocol version 6 provider servers are compatible with Terraform CLI 1.0 and later.
The following provider server implementations are supported:
- terraform-plugin-framework: A higher-level SDK that makes Terraform provider development easier by abstracting implementation details.
- terraform-plugin-go tf6server: A lower-level SDK to develop Terraform providers for more advanced use cases.
- tf5to6server: A package to translate protocol version 5 providers into protocol version 6.
Requirements
To be combined, provider servers must meet the following requirements:
- All provider schemas must match.
- All provider meta schemas must match.
- Only one provider may implement each resource and data source.
If publishing to the Terraform Registry, set metadata.protocol_versions to ["6.0"] in the Terraform Registry manifest file.
Code Implementation
Use the tf6muxserver.NewMuxServer() function to create a combined provider server. Most providers implement this in the provider main() function of the root directory main.go file or within a shared internal package to enable testing for the combined provider. You can use tf6server.WithManagedDebug() to enable debugger support.
The following example implements tf6muxserver.NewMuxServer() in a  main() function.
package main
import (
    "context"
    "flag"
    "log"
    "github.com/example/terraform-provider-example/internal/provider1"
    "github.com/example/terraform-provider-example/internal/provider2"
    "github.com/hashicorp/terraform-plugin-framework/tfsdk"
    "github.com/hashicorp/terraform-plugin-go/tfprotov6"
    "github.com/hashicorp/terraform-plugin-go/tfprotov6/tf6server"
    "github.com/hashicorp/terraform-plugin-mux/tf6muxserver"
)
var (
    // Version can be updated by goreleaser on release
    version string = "dev"
)
func main() {
    debugFlag := flag.Bool("debug", false, "Start provider in debug mode.")
    flag.Parse()
    ctx := context.Background()
    providers := []func() tfprotov6.ProviderServer{
        // Example terraform-plugin-framework providers
        providerserver.NewProtocol6(provider1.New("test")())
        providerserver.NewProtocol6(provider2.New("test")())
    }
    muxServer, err := tf6muxserver.NewMuxServer(ctx, providers...)
    if err != nil {
        log.Fatal(err)
    }
    var serveOpts []tf6server.ServeOpt
    if *debugFlag {
        serveOpts = append(serveOpts, tf6server.WithManagedDebug())
    }
    err = tf6server.Serve(
        "registry.terraform.io/example/example",
        muxServer.ProviderServer,
        serveOpts...,
    )
    if err != nil {
        log.Fatal(err)
    }
}
Testing Implementation
You can test individual providers using the same acceptance tests as before. Set the ProtoV6ProviderFactories field of TestCase with an instance of the mux server, instead of declaring the provider with other TestCase fields such as ProviderFactories.
The following example uses the acceptance testing framework to create a test for two providers.
resource.Test(t, resource.TestCase{
    // ... other TestCase fields ...
    ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error) {
        "example": func() (tfprotov6.ProviderServer, error) {
            ctx := context.Background()
            providers := []func() tfprotov6.ProviderServer{
                // Example terraform-plugin-framework providers
                providerserver.NewProtocol6(provider1.New("test")())
                providerserver.NewProtocol6(provider2.New("test")())
            }
            muxServer, err := tf6muxserver.NewMuxServer(ctx, providers...)
            if err != nil {
                return nil, err
            }
            return muxServer.ProviderServer(), nil
        },
    },
})
Refer to the acceptance tests documentation for more details.