---
page_title: 'Plugin Development - Framework: Implement Functions'
description: >-
  How to implement provider-defined functions in the provider development framework.
---

# Implement Functions

The framework supports implementing functions based on Terraform's [concepts for provider-defined functions](/terraform/plugin/framework/functions/concepts). It is recommended to understand those concepts before implementing a function since the terminology is used throughout this page and there are details that simplify function handling as compared to other provider concepts. Provider-defined functions are supported in Terraform 1.8 and later.

The main code components of a function implementation are:

* [Defining the function](#define-function-type) including its name, expected data types, descriptions, and logic.
* [Adding the function to the provider](#add-function-to-provider) so it is accessible by Terraform and practitioners.

Once the code is implemented, it is always recommended to also add:

* [Testing](/terraform/plugin/framework/functions/testing) to ensure expected function behaviors.
* [Documentation](/terraform/plugin/framework/functions/documentation) to ensure the function is discoverable by practitioners with usage information.

## Define Function Type

Implement the [`function.Function` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/function#Function). Each of the methods is described in more detail below.

In this example, a function named `echo` is defined, which takes a string argument and returns that value as the result:

```go
import (
    "github.com/hashicorp/terraform-plugin-framework/function"
)

// Ensure the implementation satisfies the desired interfaces.
var _ function.Function = &EchoFunction{}

type EchoFunction struct {}

func (f *EchoFunction) Metadata(ctx context.Context, req function.MetadataRequest, resp *function.MetadataResponse) {
    resp.Name = "echo"
}

func (f *EchoFunction) Definition(ctx context.Context, req function.DefinitionRequest, resp *function.DefinitionResponse) {
    resp.Definition = function.Definition{
        Summary:     "Echo a string",
        Description: "Given a string value, returns the same value.",

        Parameters: []function.Parameter{
            function.StringParameter{
                Name:        "input",
                Description: "Value to echo",
            },
        },
        Return: function.StringReturn{},
    }
}

func (f *EchoFunction) Run(ctx context.Context, req function.RunRequest, resp *function.RunResponse) {
    var input string

    // Read Terraform argument data into the variable
    resp.Error = function.ConcatFuncErrors(resp.Error, req.Arguments.Get(ctx, &input))

    // Set the result to the same data
    resp.Error = function.ConcatFuncErrors(resp.Error, resp.Result.Set(ctx, input))
}
```

### Metadata Method

The [`function.Function` interface `Metadata` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/function#Function.Metadata) defines the function name as it would appear in Terraform configurations. Unlike resources and data sources, this name should **NOT** include the provider name as the configuration language syntax for calling functions will separately include the provider name. Refer to [naming](/terraform/plugin/best-practices/naming) for additional best practice details.

In this example, the function name is set to `example`:

```go
// With the function.Function implementation
func (f *ExampleFunction) Metadata(ctx context.Context, req function.MetadataRequest, resp *function.MetadataResponse) {
    resp.Name = "example"
}
```

### Definition Method

The [`function.Function` interface `Definition` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/function#Function.Definition) defines the parameters, return, and various descriptions for documentation of the function.

In this example, the function definition includes one string parameter, a string return, and descriptions for documentation:

```go
func (f *ExampleFunction) Definition(ctx context.Context, req function.DefinitionRequest, resp *function.DefinitionResponse) {
    resp.Definition = function.Definition{
        Summary:     "Echo a string",
        Description: "Given a string value, returns the same value.",

        Parameters: []function.Parameter{
            function.StringParameter{
                Description: "Value to echo",
                Name:        "input",
            },
        },
        Return: function.StringReturn{},
    }
}
```

#### Return

The `Return` field must be defined as all functions must return a result. This influences how the [Run method](#run-method) must set the result data. Refer to the [returns](/terraform/plugin/framework/functions/returns) documentation for details about all available types and how to handle data with each type.

#### Parameters

There may be zero or more parameters, which are defined with the `Parameters` field. They are ordered, which influences how practitioners call the function in their configurations and how the [Run method](#run-method) must read the argument data. Refer to the [parameters](/terraform/plugin/framework/functions/parameters) documentation for details about all available types and how to handle data with each type.

An optional `VariadicParameter` field enables a final variadic parameter which accepts zero, one, or more values of the same type. It may be optionally combined with `Parameters`, meaning it represents the any argument data after the final parameter. When reading argument data, a `VariadicParameter` is represented as a tuple, with each element matching the parameter type; the tuple has zero or more elements to match the given arguments.

By default, Terraform will not pass null or unknown values to the provider logic when a function is called. Within each parameter, use the `AllowNullValue` and/or `AllowUnknownValues` fields to explicitly allow those kinds of values. Enabling `AllowNullValue` requires using a pointer type or [framework type](/terraform/plugin/framework/handling-data/types) when reading argument data. Enabling `AllowUnknownValues` requires using a [framework type](/terraform/plugin/framework/handling-data/types) when reading argument data.

#### Documentation

The [function documentation](/terraform/plugin/framework/functions/documentation) page describes how to implement documentation so it is available to Terraform, downstream tooling such as practitioner configuration editor integrations, and in the [Terraform Registry](https://registry.terraform.io).

#### Deprecation

If a function is being deprecated, such as for future removal, the `DeprecationMessage` field should be set. The message should be actionable for practitioners, such as telling them what to do with their configuration instead of calling this function.

### Run Method

The [`function.Function` interface `Run` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/function#Function.Run) defines the logic that is invoked when Terraform calls the function. Only argument data is provided when a function is called. Refer to [HashiCorp Provider Design Principles](/terraform/plugin/best-practices/hashicorp-provider-design-principles) for additional best practice details.

Implement the `Run` method by:

1. Creating variables for argument data, based on the parameter definitions. Refer to the [parameters](/terraform/plugin/framework/functions/parameters) documentation for details about all available parameter types and how to handle data with each type.
1. Reading argument data from the [`function.RunRequest.Arguments` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/function#RunRequest.Arguments).
1. Performing any computational logic.
1. Setting the result value, based on the return definition, into the [`function.RunResponse.Result` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/function#RunResponse.Result). Refer to the [returns](/terraform/plugin/framework/functions/returns) documentation for details about all available return types and how to handle data with each type.

If the logic needs to return a [function error](/terraform/plugin/framework/functions/errors), it can be added into the [`function.RunResponse.Error` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/function#RunResponse.Error).

### Reading Argument Data

The framework supports two methodologies for reading argument data from the [`function.RunRequest.Arguments` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/function#RunRequest.Arguments), which is of the [`function.ArgumentsData` type](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/function#ArgumentsData).

The first option is using the [`(function.ArgumentsData).Get()` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/function#ArgumentsData.Get) to read all arguments at once. The framework will return an error if the number and types of target variables does not match the argument data.

In this example, the parameters are defined as a boolean and string which are read into Go built-in `bool` and `string` variables since they do not opt into null or unknown value handling:

```go
func (f *ExampleFunction) Definition(ctx context.Context, req function.DefinitionRequest, resp *function.DefinitionResponse) {
    resp.Definition = function.Definition{
        // ... other fields ...
        Parameters: []function.Parameter{
            function.BoolParameter{
                Name: "bool_param",
                // ... other fields ...
            },
            function.StringParameter{
                Name: "string_param",
                // ... other fields ...
            },
        },
    }
}

func (f *ExampleFunction) Run(ctx context.Context, req function.RunRequest, resp *function.RunResponse) {
    var boolArg bool
    var stringArg string

    resp.Error = function.ConcatFuncErrors(resp.Error, req.Arguments.Get(ctx, &boolArg, &stringArg))

    // ... other logic ...
}
```

The second option is using [`(function.ArgumentsData).GetArgument()` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/function#ArgumentsData.GetArgument) to read individual arguments. The framework will return an error if the argument position does not exist or if the type of the target variable does not match the argument data.

In this example, the parameters are defined as a boolean and string and the first argument is read into a Go built-in `bool` variable since it does not opt into null or unknown value handling:

```go
func (f *ExampleFunction) Definition(ctx context.Context, req function.DefinitionRequest, resp *function.DefinitionResponse) {
    resp.Definition = function.Definition{
        // ... other fields ...
        Parameters: []function.Parameter{
            function.BoolParameter{
                Name: "bool_param",
                // ... other fields ...
            },
            function.StringParameter{
                Name: "string_param",
                // ... other fields ...
            },
        },
    }
}

func (f *ExampleFunction) Run(ctx context.Context, req function.RunRequest, resp *function.RunResponse) {
    var boolArg bool

    resp.Error = function.ConcatFuncErrors(resp.Error, req.Arguments.GetArgument(ctx, 0, &boolArg))

    // ... other logic ...
}
```

#### Reading Variadic Parameter Argument Data

The optional `VariadicParameter` field in a function definition enables a final variadic parameter which accepts zero, one, or more values of the same type. It may be optionally combined with `Parameters`, meaning it represents the argument data after the final parameter. When reading argument data, a `VariadicParameter` is represented as a tuple, with each element matching the parameter type; the tuple has zero or more elements to match the given arguments.

Use either the [framework tuple type](/terraform/plugin/framework/handling-data/types/tuple) or a Go slice of an appropriate type to match the variadic parameter `[]T`.

In this example, there is a boolean parameter and string variadic parameter, where the variadic parameter argument data is always fetched as a slice of `string`:

```go
func (f *ExampleFunction) Definition(ctx context.Context, req function.DefinitionRequest, resp *function.DefinitionResponse) {
    resp.Definition = function.Definition{
        // ... other fields ...
        Parameters: []function.Parameter{
            function.BoolParameter{
                Name: "bool_param",
                // ... other fields ...
            },
        },
        VariadicParameter: function.StringParameter{
            Name: "variadic_param",
            // ... other fields ...
        },
    }
}

func (f *ExampleFunction) Run(ctx context.Context, req function.RunRequest, resp *function.RunResponse) {
    var boolArg bool
    var stringVarg []string

    resp.Error = function.ConcatFuncErrors(resp.Error, req.Arguments.Get(ctx, &boolArg, &stringVarg))

    // ... other logic ...
}
```

If it is necessary to return a [function error](/terraform/plugin/framework/functions/errors) for a specific variadic argument, note that Terraform treats each zero-based argument position individually unlike how the framework exposes the argument data. Add the number of non-variadic parameters (if any) to the variadic argument tuple element index to ensure the error is aligned to the correct argument in the configuration.

In this example with two parameters and one variadic parameter, an error is returned for variadic arguments:

```go
func (f *ExampleFunction) Definition(ctx context.Context, req function.DefinitionRequest, resp *function.DefinitionResponse) {
    resp.Definition = function.Definition{
        // ... other fields ...
        Parameters: []function.Parameter{
            function.BoolParameter{
                Name: "bool_param",
                // ... other fields ...
            },
            function.Int64Parameter{
                Name: "int64_param",
                // ... other fields ...
            },
        },
        VariadicParameter: function.StringParameter{
            Name: "variadic_param",
            // ... other fields ...
        },
    }
}

func (f *ExampleFunction) Run(ctx context.Context, req function.RunRequest, resp *function.RunResponse) {
    var boolArg bool
    var int64Arg int64
    var stringVarg []string

    resp.Error = function.ConcatFuncErrors(resp.Error, req.Arguments.Get(ctx, &boolArg, &int64arg, &stringVarg))

    for index, element := range stringVarg {
        // Added by 2 to match the definition including two parameters.
        resp.Error = function.ConcatFuncErrors(resp.Error, function.NewArgumentFuncError(2+index, "example summary: example detail"))
    }

    // ... other logic ...
}
```

### Setting Result Data

The framework supports setting a result value into the [`function.RunResponse.Result` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/function#RunResponse.Result), which is of the [`function.ResultData` type](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/function#ResultData). The result value must match the return type, otherwise the framework or Terraform will return an error.

In this example, the return is defined as a string and a string value is set:

```go
func (f *ExampleFunction) Definition(ctx context.Context, req function.DefinitionRequest, resp *function.DefinitionResponse) {
    resp.Definition = function.Definition{
        // ... other fields ...
        Return: function.StringReturn{},
    }
}

func (f *ExampleFunction) Run(ctx context.Context, req function.RunRequest, resp *function.RunResponse) {
    // ... other logic ...

    // Value based on the return type. Returns can also use the framework type system.
    result := "hardcoded example"

    resp.Error = function.ConcatFuncErrors(resp.Error, resp.Result.Set(ctx, result))
}
```

## Add Function to Provider

Functions become available to practitioners when they are included in the [provider](/terraform/plugin/framework/providers) implementation via the [`provider.ProviderWithFunctions` interface `Functions` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#ProviderWithFunctions.Functions).

In this example, the `EchoFunction` type, which implements the `function.Function` interface, is added to the provider implementation:

```go
// With the provider.Provider implementation
func (p *ExampleCloudProvider) Functions(_ context.Context) []func() function.Function {
    return []func() function.Function{
        func() function.Function {
            return &EchoFunction{},
        },
    }
}
```

To simplify provider implementations, a named function can be created with the function implementation.

In this example, the `EchoFunction` code includes an additional `NewEchoFunction` function, which simplifies the provider implementation:

```go
// With the provider.Provider implementation
func (p *ExampleCloudProvider) Functions(_ context.Context) []func() function.Function {
    return []func() function.Function{
        NewEchoFunction,
    }
}

// With the function.Function implementation
func NewEchoFunction() function.Function {
    return &EchoFunction{}
}
```
