• HashiCorp Developer

  • HashiCorp Cloud Platform
  • Terraform
  • Packer
  • Consul
  • Vault
  • Boundary
  • Nomad
  • Waypoint
  • Vagrant
Terraform
  • Install
  • Tutorials
    • About the Docs
    • Configuration Language
    • Terraform CLI
    • Terraform Cloud
    • Terraform Enterprise
    • CDK for Terraform
    • Provider Use
    • Plugin Development
    • Registry Publishing
    • Integration Program
  • Registry(opens in new tab)
  • Try Cloud(opens in new tab)
  • Sign up
Custom Framework Providers

Skip to main content
11 tutorials
  • Implement a Provider with the Terraform Plugin Framework
  • Configure Provider Client
  • Implement Data Source
  • Implement Logging
  • Implement Resource Create and Read
  • Implement Resource Update
  • Implement Resource Delete
  • Implement Resource Import
  • Implement Automated Testing
  • Implement Documentation Generation
  • Release and Publish to the Terraform Registry

  • Resources

  • Tutorial Library
  • Certifications
  • Community Forum
    (opens in new tab)
  • Support
    (opens in new tab)
  • GitHub
    (opens in new tab)
  • Terraform Registry
    (opens in new tab)
  1. Developer
  2. Terraform
  3. Tutorials
  4. Custom Framework Providers
  5. Implement a Provider with the Terraform Plugin Framework

Implement a Provider with the Terraform Plugin Framework

  • 10min

  • TerraformTerraform

In these tutorials, you will write a custom provider against the API of a fictional coffee-shop application called HashiCups using the Terraform Plugin Framework. Through the process, you will learn how to create data sources, authenticate the provider to the HashiCups client, and how providers map target APIs to Terraform in order to create, read, update, and delete resources.

There are a several reasons to author a custom Terraform provider, including:

  • Enabling users of your product to provision components with Terraform.
  • Enabling users of internal products and services to provision components with Terraform.
  • Extending the capabilities of an existing provider by fixing bugs or adding new features and customization options.

In this tutorial, you will set up your Terraform provider development environment and create an initial provider that can communicate with Terraform. To do this, you will:

  1. Set up your development environment.
    You will clone the HashiCups repository and checkout the boilerplate branch. This contains a scaffold for a generic Terraform provider.
  2. Define the provider type.
    This prepares the provider code for all future implementation details, such as implementing data sources and resources.
  3. Define the provider server.
    This prepares the provider code to communicate with Terraform on startup.

Prerequisites

To follow this tutorial, you need:

  • Go 1.18+ installed and configured.
  • Terraform v1.0.3+ installed locally.
  • Docker and Docker Compose to run an instance of HashiCups locally.

Set up your development environment

Clone the boilerplate branch of the Terraform HashiCups Provider repository.

$ git clone --branch boilerplate https://github.com/hashicorp/terraform-provider-hashicups-pf

Change into the cloned repository.

$ cd terraform-provider-hashicups-pf

The directory will have the following structure.

$ tree -L 3
.
├── Makefile
├── README.md
├── docker_compose
│   ├── conf.json
│   └── docker-compose.yml
├── examples
│   ├── coffees
│   │   └── main.tf
│   ├── order
│   │   └── main.tf
│   └── provider-install-verification
│       └── main.tf
└── go.mod

If you are stuck at any point during this tutorial, refer to the provider branch in the example repository to see the changes implemented in this tutorial.

Explore your development environment

The boilerplate includes the following:

  • Makefile contains helper functions used to generate, install, and test the HashiCups provider.
  • docker_compose contains the Docker configuration required to launch a local instance of HashiCups.
  • examples contains sample Terraform configuration that you will use to manually test the HashiCups provider.
  • go.mod contains an initialized Go module that you will update throughout these tutorials.

Implement initial provider type

Providers use an implementation of the provider.Provider interface type as the starting point for all implementation details.

This interface requires the following:

  1. A Metadata method to define the provider type name for inclusion in each data source and resource type name. For example, a resource type named "hashicups_order" would have a provider type name of "hashicups".
  2. A Schema method to define the schema for provider-level configuration. Later in these tutorials, you will update this method to accept a HashiCups API token and endpoint.
  3. A Configure method to configure shared clients for data source and resource implementations.
  4. A DataSources method to define the provider's data sources.
  5. A Resources method to define the provider's resources.

Create a hashicups directory in the repository you cloned, which will contain all the Go code for the provider except the provider server.

$ mkdir hashicups

Create a hashicups/provider.go file with the following.

hashicups/provider.go
package hashicups

import (
    "context"

    "github.com/hashicorp/terraform-plugin-framework/datasource"
    "github.com/hashicorp/terraform-plugin-framework/provider"
    "github.com/hashicorp/terraform-plugin-framework/provider/schema"
    "github.com/hashicorp/terraform-plugin-framework/resource"
)

// Ensure the implementation satisfies the expected interfaces
var (
    _ provider.Provider = &hashicupsProvider{}
)

// New is a helper function to simplify provider server and testing implementation.
func New() provider.Provider {
    return &hashicupsProvider{}
}

// hashicupsProvider is the provider implementation.
type hashicupsProvider struct{}

// Metadata returns the provider type name.
func (p *hashicupsProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
    resp.TypeName = "hashicups"
}

// Schema defines the provider-level schema for configuration data.
func (p *hashicupsProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
    resp.Schema = schema.Schema{}
}

// Configure prepares a HashiCups API client for data sources and resources.
func (p *hashicupsProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
}

// DataSources defines the data sources implemented in the provider.
func (p *hashicupsProvider) DataSources(_ context.Context) []func() datasource.DataSource {
    return nil
}

// Resources defines the resources implemented in the provider.
func (p *hashicupsProvider) Resources(_ context.Context) []func() resource.Resource {
    return nil
}

Implement the provider server

Terraform providers are server processes that Terraform interacts with to handle each data source and resource operation, such as creating a resource on a remote system. Later in these tutorials, you will connect those Terraform operations to a locally running HashiCups API.

Serving a provider follows these steps:

  1. Starts a provider server process. By implementing the main function, which is the code execution starting point for Go language programs, a long-running server will listen for Terraform requests.

Framework provider servers also support optional functionality such as enabling support for debugging tools. You will not implement this functionality in these tutorials.

Create a main.go file in the terraform-provider-hashicups-pf repository's root directory with the following code.

main.go
package main

import (
    "context"
    "terraform-provider-hashicups-pf/hashicups"

    "github.com/hashicorp/terraform-plugin-framework/providerserver"
)

func main() {
    providerserver.Serve(context.Background(), hashicups.New, providerserver.ServeOpts{
        // NOTE: This is not a typical Terraform Registry provider address,
        // such as registry.terraform.io/hashicorp/hashicups. This specific
        // provider address is used in these tutorials in conjunction with a
        // specific Terraform CLI configuration for manual development testing
        // of this provider.
        Address: "hashicorp.com/edu/hashicups-pf",
    })
}

Install Go dependencies

The provider type and provider server code imports new external dependencies to this codebase. Use the go get command to download these dependencies.

$ go get github.com/hashicorp/terraform-plugin-framework@latest
go: downloading github.com/hashicorp/terraform-plugin-framework v1.0.0
go: added github.com/hashicorp/terraform-plugin-framework v1.0.0

Ensure that all Go dependencies are resolved.

$ go mod tidy
go: downloading github.com/hashicorp/terraform-plugin-go v0.14.2

Verify the initial provider

With the Go dependencies ready, your provider code should compile and run. Verify that your development environment is working properly by executing the code directly. This will return an error message as this is not how Terraform normally starts provider servers, but the error indicates that Go was able to compile and run your provider server.

Manually run the provider.

$ go run main.go
This binary is a plugin. These are not meant to be executed directly.
Please execute the program that consumes these plugins, which will
load any plugins automatically
exit status 1

Prepare Terraform for local provider install

Terraform installs providers and verifies their versions and checksums when you run terraform init. Terraform will download your providers from either the provider registry or a local registry. However, while building your provider you will want to test Terraform configuration against a local development build of the provider. The development build will not have an associated version number or an official set of checksums listed in a provider registry.

Terraform allows you to use local provider builds by setting a dev_overrides block in a configuration file called .terraformrc. This block overrides all other configured installation methods.

Terraform searches for the .terraformrc file in your home directory and applies any configuration settings you set.

First, find the GOBIN path where Go installs your binaries. Your path may vary depending on how your Go environment variables are configured.

$ go env GOBIN
/Users/<Username>/go/bin

If the GOBIN go environment variable is not set, use the default path, /Users/<Username>/go/bin.

Create a new file called .terraformrc in your home directory (~), then add the dev_overrides block below. Change the <PATH> to the value returned from the go env GOBIN command above.

~/.terraformrc
provider_installation {

  dev_overrides {
      "hashicorp.com/edu/hashicups-pf" = "<PATH>"
  }

  # For all other providers, install them directly from their origin provider
  # registries as normal. If you omit this, Terraform will _only_ use
  # the dev_overrides block, and so no other providers will be available.
  direct {}
}

You must create your CLI configuration file in your user's %APPDATA% directory. The physical location of this directory depends on your Windows version and system configuration.

Search for the user environment variables in PowerShell to find its location on your system.

$ $env:APPDATA

In another terminal, change into the directory returned from the command above.

$ cd /APPDATA_DIR

Find the GOBIN path where go installs your binaries. Your path may vary depending on how your Go environment variables are configured.

$ go env GOBIN
/Users/<Username>/go/bin

If the GOBIN go environment variable is not set, use the default path, /Users/<Username>/go/bin.

Create a new file in your APPDATA directory called terraform.rc and add the dev_overrides block below. Change the <PATH> to the value returned from the go env GOBIN command above.

terraform.rc
provider_installation {

  dev_overrides {
      "hashicorp.com/edu/hashicups-pf" = "<PATH>"
      }

  # For all other providers, install them directly from their origin provider
  # registries as normal. If you omit this, Terraform will _only_ use
  # the dev_overrides block, and so no other providers will be available.
  direct {}
}

Locally install provider and verify with Terraform

Your Terraform CLI is now ready to use the locally installed provider in the GOBIN path. Use the go install command from the example repository's root directory to compile the provider into a binary and install it in your GOBIN path.

$ go install .

Navigate to the examples/provider-install-verification directory.

$ cd examples/provider-install-verification

The main.tf Terraform configuration file in this directory uses a "hashicups_coffees" data source that the provider does not yet support. You will implement this data source in a future tutorial.

examples/provider-install-verification/main.tf
terraform {
  required_providers {
    hashicups = {
      source = "hashicorp.com/edu/hashicups-pf"
    }
  }
}

provider "hashicups" {}

data "hashicups_coffees" "example" {}

Running a Terraform plan will report the provider override, as well as an error about the missing data source. Even though there was an error, this verifies that Terraform was able to successfully start the locally installed provider and interact with it in your development environment.

Run a Terraform plan with the non-existent data source. Terraform will respond with the missing data source error.

$ terraform plan
â•·
│ Warning: Provider development overrides are in effect
│
│ The following provider development overrides are set in the CLI
│ configuration:
│  - hashicorp.com/edu/hashicups-pf in /Users/<Username>/go/bin
│
│ The behavior may therefore not match any released version of the provider and
│ applying changes may cause the state to become incompatible with published
│ releases.
╵
â•·
│ Error: Invalid data source
│ 
│   on main.tf line 11, in data "hashicups_coffees" "example":
│   11: data "hashicups_coffees" "example" {}
│ 
│ The provider hashicorp.com/edu/hashicups-pf does not support data source
│ "hashicups_coffees".
╵

Navigate to the terraform-provider-hashicups-pf directory.

$ cd ../..

Next steps

Congratulations! You have started development of your own custom Terraform provider. Later tutorials will show you how to implement data source and resource functionality.

If you were stuck during this tutorial, checkout the provider branch to see the changes implemented in this tutorial.

  • To learn more about the Terraform Plugin Framework, refer to the Terraform Plugin Framework documentation.
  • For a full capability comparison between the SDKv2 and the Plugin Framework, refer to the Which SDK Should I Use? documentation.
  • The Terraform HashiCups (plugin-framework) provider's main branch contains the complete HashiCups provider. It includes a data source written with the plugin framework and implements create, read, update, and delete functionality for the order resource.
  • Submit any Terraform Plugin Framework bug reports or feature requests to the development team in the Terraform Plugin Framework Github repository.
  • Submit any Terraform Plugin Framework questions in the Terraform Plugin Framework Discuss forum.
 Back to Collection
 Next

On this page

  1. Implement a Provider with the Terraform Plugin Framework
  2. Prerequisites
  3. Set up your development environment
  4. Explore your development environment
  5. Implement initial provider type
  6. Implement the provider server
  7. Install Go dependencies
  8. Verify the initial provider
  9. Prepare Terraform for local provider install
  10. Locally install provider and verify with Terraform
  11. Next steps
Give Feedback(opens in new tab)
  • Certifications
  • System Status
  • Terms of Use
  • Security
  • Privacy
  • Trademark Policy
  • Trade Controls
  • Give Feedback(opens in new tab)