---
page_title: 'Plugin Development - Framework: Getting Started - Code Walkthrough'
description: >-
  How to setup and configure a simple plugin provider.
---

# Code Walkthrough

[Terraform providers](/terraform/language/providers) let Terraform communicate with third parties, such as cloud providers, SaaS providers, and other APIs. Terraform and Terraform providers use gRPC to communicate. Terraform operates as a gRPC client and providers operate as gRPC servers.

Each provider defines resources that let Terraform manage infrastructure objects and data sources that let Terraform read data. Terraform practitioners then write configuration to define resources, such as compute storage or networking resources. Terraform then communicates this configuration to the provider, and the provider creates the infrastructure.

This example provider shows the relationship between the required provider components. The resources and data sources in a typical provider interact with a cloud provider through an API, but the example only stores values in state.

## Core Provider Components

A Terraform plugin provider requires at least the following components:

- [provider server](#provider-server)
- [provider](#provider)
- [resource](#resource) or [data source](#data-source)

The provider wraps the resource(s) and/or data source(s), and can be used to configure a client which communicates with a 3rd party service via an API.
Resources are used to manage infrastructure objects.
Data sources are used to read infrastructure objects.

## Provider Server

Each provider must implement a gRPC server that supports Terraform-specific connection and handshake handling on startup. A [provider server](/terraform/plugin/framework/provider-servers) is required in order for a Terraform provider to:

* expose resources that can be managed by Terraform core.
* expose data sources that can be read by Terraform core.

The `main()` function is used for defining a provider server.

The `provider.New()` returns a function which returns a type that satisfies the `provider.Provider` interface. The `provider.Provider` interface defines functions for obtaining the resource(s) and/or data source(s) from a provider.

```go
package main

import (
    "context"
    "flag"
    "log"

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

    "github.com/example_namespace/terraform-provider-example/internal/provider"
)

func main() {
    var debug bool

    flag.BoolVar(&debug, "debug", false, "set to true to run the provider with support for debuggers like delve")
    flag.Parse()

    opts := providerserver.ServeOpts{
        Address: "registry.terraform.io/example_namespace/example",
        Debug:   debug,
    }

    err := providerserver.Serve(context.Background(), provider.New(), opts)

    if err != nil {
        log.Fatal(err.Error())
    }
}
```

Refer to [Provider Servers](/terraform/plugin/framework/provider-servers) for more details.

## Provider

The provider wraps resources and data sources which are typically used for interacting with cloud providers, SaaS providers, or other APIs.

In this example the provider wraps a resource and a data source which simply interact with Terraform state. Refer to the [tutorial](/terraform/tutorials/providers-plugin-framework/providers-plugin-framework-provider-configure) for an example of provider configuration that configures an API client.

`New()` returns a function which returns a type that satisfies the `provider.Provider` interface. The `New()` function is called by the [provider server](#provider-server) to obtain the provider.

The `exampleProvider` struct implements the `provider.Provider` interface. This interface defines the following functions:

- [`Schema`](/terraform/plugin/framework/handling-data/schemas): This function returns a provider `schema.Schema` struct that defines the provider schema. Schemas specify the constraints of Terraform configuration blocks. They define what fields a provider, resource, or data source configuration block has, and give Terraform metadata about those fields.
- [`Configure`](/terraform/plugin/framework/providers#configure-method): This function lets you configure provider-level data or clients. These configuration values may be from the practitioner Terraform configuration as defined by the schema, environment variables, or other means such as reading vendor-specific configuration files.
- [`Resources`](/terraform/plugin/framework/providers#resources): This function returns a slice of functions that return types that implement the `resource.Resource` interface. Resources let Terraform manage infrastructure objects, such as a compute instance, an access policy, or disk.
- [`Data Sources`](/terraform/plugin/framework/providers#datasources): This function returns a slice of functions that return types which implement the `datasource.DataSource` interface. Data sources let Terraform reference external data. For example a database instance.

The `exampleProvider` struct also implements the `provider.ProviderWithMetadata` interface which defines the `Metadata` function. The `Metadata` function returns metadata for the provider such as a `TypeName` and `Version`. The `TypeName` is used as a prefix within a provider by for naming [resources](#resource) and [data sources](#data-source).

```go
package provider

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"
    "github.com/hashicorp/terraform-plugin-framework/types"
)

var _ provider.Provider = (*exampleProvider)(nil)
var _ provider.ProviderWithMetadata = (*exampleProvider)(nil)

type exampleProvider struct{}

func New() func() provider.Provider {
    return func() provider.Provider {
        return &exampleProvider{}
    }
}

func (p *exampleProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
}

func (p *exampleProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
    resp.TypeName = "example"
}

func (p *exampleProvider) DataSources(ctx context.Context) []func() datasource.DataSource {
    return []func() datasource.DataSource{
        NewDataSource,
    }
}

func (p *exampleProvider) Resources(ctx context.Context) []func() resource.Resource {
    return []func() resource.Resource{
        NewResource,
    }
}

func (p *exampleProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) {
}
```

Refer to [Providers](/terraform/plugin/framework/providers) for more details and configuration examples.

## Resource

A resource is typically used to manage infrastructure objects such as virtual networks and compute instances.

In this example the resource simply interacts with Terraform state.

`NewResource()` returns a function which returns a type that satisfies the `resource.Resource` interface. The provider calls the `NewResource()` function within `provider.Resources` to obtain an instance of the resource.

The `exampleResource` struct implements the `resource.Resource` interface. This interface defines the following functions:

- [`Metadata`](/terraform/plugin/framework/resources#metadata-method): This function returns the full name (`TypeName`) of the resource. The full name is used in [Terraform configuration](#resource-configuration) as `resource <full name> <alias>`.
- [`Schema`](/terraform/plugin/framework/handling-data/schemas): This function returns a resource `schema.Schema` struct that defines the resource schema. The schema specifies the constraints of the resource Terraform configuration block. It defines what fields a resource configuration block has, and gives Terraform metadata about those fields. For instance, defining whether a field is required.
- [`Create`](/terraform/plugin/framework/resources/create): This function lets the provider create a new resource of this type.
- [`Read`](/terraform/plugin/framework/resources/read): This function lets the provider read resource values in order to update state.
- [`Update`](/terraform/plugin/framework/resources/update): This function lets the provider update the resource and state.
- [`Delete`](/terraform/plugin/framework/resources/delete): This function lets the provider delete the resource.

```go
package provider

import (
    "context"

    "github.com/hashicorp/terraform-plugin-framework/path"
    "github.com/hashicorp/terraform-plugin-framework/resource"
    "github.com/hashicorp/terraform-plugin-framework/resource/schema"
    "github.com/hashicorp/terraform-plugin-framework/types"
    "github.com/hashicorp/terraform-plugin-log/tflog"
)

var _ resource.Resource = (*exampleResource)(nil)

type exampleResource struct {
    provider exampleProvider
}

func NewResource() resource.Resource {
    return &exampleResource{}
}

func (e *exampleResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
    resp.TypeName = req.ProviderTypeName + "_resource"
}

func (e *exampleResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
    resp.Schema = schema.Schema{
        Attributes: map[string]schema.Attribute{
            "configurable_attribute": schema.StringAttribute{
                Optional:            true,
            },
            "id": schema.StringAttribute{
                Computed:            true,
                PlanModifiers: []planmodifier.String{
                    stringplanmodifier.UseStateForUnknown(),
                },
            },
        },
    }
}

type exampleResourceData struct {
    ConfigurableAttribute types.String `tfsdk:"configurable_attribute"`
    Id                    types.String `tfsdk:"id"`
}

func (e *exampleResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
    var data exampleResourceData

    diags := req.Config.Get(ctx, &data)
    resp.Diagnostics.Append(diags...)

    if resp.Diagnostics.HasError() {
        return
    }

	// Create resource using 3rd party API.

    data.Id = types.StringValue("example-id")

    tflog.Trace(ctx, "created a resource")

    diags = resp.State.Set(ctx, &data)
    resp.Diagnostics.Append(diags...)
}

func (e *exampleResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
    var data exampleResourceData

    diags := req.State.Get(ctx, &data)
    resp.Diagnostics.Append(diags...)

    if resp.Diagnostics.HasError() {
        return
    }

	// Read resource using 3rd party API.

    diags = resp.State.Set(ctx, &data)
    resp.Diagnostics.Append(diags...)
}

func (e *exampleResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
    var data exampleResourceData

    diags := req.Plan.Get(ctx, &data)
    resp.Diagnostics.Append(diags...)

    if resp.Diagnostics.HasError() {
        return
    }

	// Update resource using 3rd party API.

    diags = resp.State.Set(ctx, &data)
    resp.Diagnostics.Append(diags...)
}

func (e *exampleResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
    var data exampleResourceData

    diags := req.State.Get(ctx, &data)
    resp.Diagnostics.Append(diags...)

    if resp.Diagnostics.HasError() {
        return
    }

	// Delete resource using 3rd party API.
}
```

Refer to [Resources](/terraform/plugin/framework/resources) for more details and configuration examples.

## Data Source

A data source is typically used to provide a read-only view of infrastructure objects.

In this example the data source simply interacts with Terraform state.

`NewDataSource()` returns a function which returns a type that satisfies the `datasource.DataSource` interface. The `NewDataSource()` function is used within the `provider.DataSources` function to make the data source available to the provider.

The `exampleDataSource` struct implements the `datasource.DataSource` interface. This interface defines the following functions:

- [`Metadata`](/terraform/plugin/framework/data-sources#metadata-method): This function returns the full name (`TypeName`) of the data source. The full name is used in [Terraform configuration](#data-source-configuration) as `data <full name> <alias>`.
- [`Schema`](/terraform/plugin/framework/handling-data/schemas): This function returns a data source `schema.Schema` struct that defines the data source schema. The schema specifies the constraints of the data source Terraform configuration block. It defines what fields a data source configuration block has, and gives Terraform metadata about those fields. For instance, defining whether a field is optional.
- [`Read`](/terraform/plugin/framework/data-sources#read-method): This function lets the provider read data source values in order to update state.

```go
package provider

import (
    "context"

    "github.com/hashicorp/terraform-plugin-framework/datasource"
    "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
    "github.com/hashicorp/terraform-plugin-framework/types"
    "github.com/hashicorp/terraform-plugin-log/tflog"
)

var _ datasource.DataSource = (*exampleDataSource)(nil)

type exampleDataSource struct {
    provider exampleProvider
}

func NewDataSource() datasource.DataSource {
    return &exampleDataSource{}
}

func (e *exampleDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
    resp.TypeName = req.ProviderTypeName + "_datasource"
}

func (e *exampleDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
    resp.Schema = schema.Schema{
        Attributes: map[string]schema.Attribute{
            "configurable_attribute": schema.StringAttribute{
                MarkdownDescription: "Example configurable attribute",
                Optional:            true,
            },
            "id": schema.StringAttribute{
                MarkdownDescription: "Example identifier",
                Computed:            true,
            },
        },
    }
}

type exampleDataSourceData struct {
    ConfigurableAttribute types.String `tfsdk:"configurable_attribute"`
    Id                    types.String `tfsdk:"id"`
}

func (e *exampleDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
    var data exampleDataSourceData

    diags := req.Config.Get(ctx, &data)
    resp.Diagnostics.Append(diags...)

    if resp.Diagnostics.HasError() {
        return
    }

	// Interact with 3rd party API to read data source.

    data.Id = types.StringValue("example-id")

    tflog.Trace(ctx, "read a data source")

    diags = resp.State.Set(ctx, &data)
    resp.Diagnostics.Append(diags...)
}
```

Refer to [Data Sources](/terraform/plugin/framework/data-sources) for more details and configuration examples.

## Terraform Configuration

Refer to [terraform-provider-scaffolding-framework](https://github.com/hashicorp/terraform-provider-scaffolding-framework) for details on how to wire together a [provider server](#provider-server), [provider](#provider), [resource](#resource) and [data source](#data-source).

Once wired together, run the provider by specifying configuration and executing `terraform apply`.

### Resource Configuration

```hcl
resource "example_resource" "example" {
  configurable_attribute = "some-value"
}
```

The `configurable_attribute` is defined within the [schema](#resource) as a string type attribute.

Examples of the various types of attributes and their representation within Terraform configuration and schema definitions are detailed in [Terraform Concepts](/terraform/plugin/framework/handling-data/terraform-concepts).

### Data Source Configuration

```hcl
data "example_datasource" "example" {
  configurable_attribute = "some-value"
}
```

The `configurable_attribute` is defined within the [schema](#data-source) as a string type attribute.

Examples of the various types of attributes and their representation within Terraform configuration and schema definitions are detailed in [Terraform Concepts](/terraform/plugin/framework/handling-data/terraform-concepts).
