---
page_title: 'Plugin Development - Framework: Dynamic Type'
description: >-
  Learn the dynamic value type in the provider development framework.
---

# Dynamic Type

<Tip>

Static types should always be preferred over dynamic types, when possible.

Developers dealing with dynamic data will need to have extensive knowledge of the [Terraform type system](/terraform/language/expressions/types) to properly handle all potential practitioner configuration scenarios.

Refer to [Dynamic Data - Considerations](/terraform/plugin/framework/handling-data/dynamic-data#considerations) for more information.

</Tip>

Dynamic is a container type that can have an underlying value of **any** type.

By default, dynamic values from [schema](/terraform/plugin/framework/handling-data/schemas) (configuration, plan, and state) data are represented in the framework by [`types.DynamicType`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types#DynamicType) and its associated value storage type of [`types.Dynamic`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types#Dynamic). These types fully support Terraform's [type system concepts](/terraform/plugin/framework/handling-data/terraform-concepts) that cannot be represented in Go built-in types. Framework types can be [extended](#extending) by provider code or shared libraries to provide specific use case functionality.

## Schema Definitions

Use one of the following attribute types to directly add a dynamic value to a [schema](/terraform/plugin/framework/handling-data/schemas) or [nested attribute type](/terraform/plugin/framework/handling-data/attributes#nested-attribute-types):

| Schema Type | Attribute Type |
|-------------|----------------|
| [Data Source](/terraform/plugin/framework/data-sources) | [`schema.DynamicAttribute`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/datasource/schema#DynamicAttribute) |
| [Provider](/terraform/plugin/framework/provider) | [`schema.DynamicAttribute`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider/schema#DynamicAttribute) |
| [Resource](/terraform/plugin/framework/resources) | [`schema.DynamicAttribute`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource/schema#DynamicAttribute) |

Dynamic values are not supported as the element type of a [collection type](/terraform/plugin/framework/handling-data/types#collection-types) or within [collection attribute types](/terraform/plugin/framework/handling-data/attributes#collection-attribute-types).

If the dynamic value should be a value type of an [object attribute type](/terraform/plugin/framework/handling-data/attributes#object-attribute-type), set the `AttrTypes` map value to `types.DynamicType` or the appropriate [custom type](#extending).

## Accessing Values

<Tip>

Review the [attribute documentation](/terraform/plugin/framework/handling-data/attributes/dynamic#accessing-values) to understand how schema-based data gets mapped into accessible values, such as a `types.Dynamic` in this case.

</Tip>

Access `types.Dynamic` information via the following methods:

* [`(types.Dynamic).IsNull() bool`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/basetypes#DynamicValue.IsNull): Returns true if the dynamic value is null.
* [`(types.Dynamic).IsUnderlyingValueNull() bool`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/basetypes#DynamicValue.IsUnderlyingValueNull): Returns true if the dynamic value is known but the underlying value is null. See the [Dynamic Data section](/terraform/plugin/framework/handling-data/dynamic-data#handling-underlying-null-and-unknown-values) for more information about null underlying values.
* [`(types.Dynamic).IsUnknown() bool`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/basetypes#DynamicValue.IsUnknown): Returns true if the dynamic value is unknown.
* [`(types.Dynamic).IsUnderlyingValueUnknown() bool`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/basetypes#DynamicValue.IsUnderlyingValueUnknown): Returns true if the dynamic value is known but the underlying value is unknown. See the [Dynamic Data section](/terraform/plugin/framework/handling-data/dynamic-data#handling-underlying-null-and-unknown-values) for more information about unknown underlying values.
* [`(types.Dynamic).UnderlyingValue() attr.Value`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/basetypes#DynamicValue.UnderlyingValue): Returns the underlying value of the dynamic container, will be `nil` if null or unknown.

In this example, a dynamic value is checked for being null or unknown value first, before accessing its known value:

```go
// Example data model definition
// type ExampleModel struct {
//   ExampleAttribute types.Dynamic `tfsdk:"example_attribute"`
// }
//
// This would be filled in, such as calling: req.Plan.Get(ctx, &data)
var data ExampleModel

// optional logic for handling null value
if data.ExampleAttribute.IsNull() {
    // ...
}

// optional logic for handling unknown value
if data.ExampleAttribute.IsUnknown() {
    // ...
}

// myDynamicVal now contains the underlying value, determined by Terraform at runtime
myDynamicVal := data.ExampleAttribute.UnderlyingValue()
```

### Handling the Underlying Value

If a dynamic value is known, a [Go type switch](https://go.dev/tour/methods/16) can be used to access the type-specific methods for data handling:

```go
	switch value := data.ExampleAttribute.UnderlyingValue().(type) {
	case types.Bool:
		// Handle boolean value
	case types.Number:
		// Handle float64, int64, and number values
	case types.List:
		// Handle list value
	case types.Map:
		// Handle map value
	case types.Object:
		// Handle object value
	case types.Set:
		// Handle set value
	case types.String:
		// Handle string value
	case types.Tuple:
		// Handle tuple value
	}
```

<Tip>

[Float64](/terraform/plugin/framework/handling-data/types/float64) and [Int64](/terraform/plugin/framework/handling-data/types/int64) framework types will never appear in the underlying value as both are represented as the Terraform type [`number`](/terraform/language/expressions/types#number).

</Tip>

The type of the underlying value is determined at runtime by Terraform if the value is from configuration. Developers dealing with dynamic data will need to have extensive knowledge of the [Terraform type system](/terraform/language/expressions/types) to properly handle all potential practitioner configuration scenarios.

Refer to the [Dynamic Data](/terraform/plugin/framework/handling-data/dynamic-data) documentation for more information.

## Setting Values

Call one of the following to create a `types.Dynamic` value:

* [`types.DynamicNull()`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types#DynamicNull): A null dynamic value.
* [`types.DynamicUnknown()`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types#DynamicUnknown): An unknown dynamic value where the final static type is not known. Use `types.DynamicValue()` with an unknown value if the final static type is known.
* [`types.DynamicValue(attr.Value)`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types#DynamicValue): A known dynamic value, with an underlying value determined by the `attr.Value` input.

In this example, a known dynamic value is created, where the underlying value is a known string value:

```go
types.DynamicValue(types.StringValue("hello world!"))
```

In this example, a known dynamic value is created, where the underlying value is a known object value:

```go
elementTypes := map[string]attr.Type{
    "attr1": types.StringType,
    "attr2": types.Int64Type,
}
elements := map[string]attr.Value{
    "attr1": types.StringValue("value"),
    "attr2": types.Int64Value(123),
}
objectValue, diags := types.ObjectValue(elementTypes, elements)
// ... handle any diagnostics ...

types.DynamicValue(objectValue)
```

There are no reflection rules defined for creating dynamic values, meaning they must be created using the `types` implementation.

In this example, a `types.Dynamic` with a known boolean value is used to set a dynamic attribute value:

```go
diags := resp.State.SetAttribute(ctx, path.Root("example_attribute"), types.DynamicValue(types.BoolValue(true)))
```

## Extending

The framework supports extending its base type implementations with [custom types](/terraform/plugin/framework/handling-data/types/custom). These can adjust expected provider code usage depending on their implementation.
