---
page_title: 'Plugin Development - Framework: Handling Data - Dynamic Data'
description: >-
  How to handle data when utilizing dynamic types.
---

# Dynamic Data

<Note>

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

</Note>

Dynamic data handling uses the [framework dynamic type](/terraform/plugin/framework/handling-data/types/dynamic) to communicate to Terraform that the value type of a specific field will be determined at runtime. This allows a provider developer to handle multiple value types of data with a single attribute, parameter, or return.

Dynamic data can be defined with:
- [Dynamic attribute](/terraform/plugin/framework/handling-data/attributes/dynamic)
- A [dynamic](/terraform/plugin/framework/handling-data/types/dynamic) attribute type in an [object attribute](/terraform/plugin/framework/handling-data/attributes/object)
- [Dynamic function parameter](/terraform/plugin/framework/functions/parameters/dynamic)
- [Dynamic function return](/terraform/plugin/framework/functions/returns/dynamic)
- A [dynamic](/terraform/plugin/framework/handling-data/types/dynamic) attribute type in an [object parameter](/terraform/plugin/framework/functions/parameters/object)
- A [dynamic](/terraform/plugin/framework/handling-data/types/dynamic) attribute type in an [object return](/terraform/plugin/framework/functions/returns/object)

Using dynamic data has a negative impact on practitioner experience when using Terraform and downstream tooling, like practitioner configuration editor integrations. Dynamics do not change how [Terraform's static type system](/terraform/language/expressions/types) behaves and all data consistency rules are applied the same as static types. Provider developers should understand all the below [considerations](#considerations) when creating a provider with a dynamic type.

Only use a dynamic type when there is not a suitable static type alternative.

## Considerations

When dynamic data is used, Terraform will no longer have any static information about the value types expected for a given attribute, function parameter, or function return. This results in behaviors that the provider developer will need to account for with additional documentation, code, error messaging, etc.

### Downstream Tooling

Practitioner configuration editor integrations, like the Terraform VSCode extension and language server, cannot provide any static information when using dynamic data in configurations. This can result in practitioners using dynamic data in expressions (like [`for`](/terraform/language/expressions/for)) incorrectly that will only error at runtime.

Given this example, a resource schema defines a top level computed [dynamic attribute](/terraform/plugin/framework/handling-data/attributes/dynamic) named `example_attribute`:

```go
func (r ThingResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
    resp.Schema = schema.Schema{
        Attributes: map[string]schema.Attribute{
            "example_attribute": schema.DynamicAttribute{
                Computed: true,
                // ... potentially other fields ...
            },
            // ... potentially other attributes ...
        },
    }
}
```

The configuration below would be valid until a practitioner runs an apply. If the type of `example_attribute` is not iterable, then the practitioner will receive an error only when they run a command:

```hcl
resource "examplecloud_thing" "example" {}

output "dynamic_output" {
  value = [for val in examplecloud_thing.example.example_attribute : val]
}
```

Results in the following error:

```bash
│ Error: Iteration over non-iterable value
│ 
│   on resource.tf line 15, in output "dynamic_output":
│   15:   value = [for val in examplecloud_thing.example.example_attribute : val]
│     ├────────────────
│     │ examplecloud_thing.example.example_attribute is "string value"
│ 
│ A value of type string cannot be used as the collection in a 'for' expression.
```

Dynamic data that is meant for practitioners to utilize in configurations should document all potential output types and expected usage to avoid confusing errors.

### Handling All Possible Types

Terraform will not [automatically convert](/terraform/language/expressions/types#type-conversion) values to conform to a static type, exposing provider developers to the Terraform type system directly. Provider developers will need to deal with this lack of type conversion by writing logic that handles [every possible type](/terraform/language/expressions/types#types) that Terraform supports.

In this example, a resource schema defines a top level required [dynamic attribute](/terraform/plugin/framework/handling-data/attributes/dynamic) named `example_attribute`:

```go
func (r ThingResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
    resp.Schema = schema.Schema{
        Attributes: map[string]schema.Attribute{
            "example_attribute": schema.DynamicAttribute{
                Required: true,
                // ... potentially other fields ...
            },
            // ... potentially other attributes ...
        },
    }
}
```

An example of handling every possible Terraform type that could be provided to a configuration would be:

```go
    // Example data model definition
    // type ExampleModel struct {
    //   ExampleAttribute types.Dynamic `tfsdk:"example_attribute"`
    // }
    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
    }
```

When writing test configurations and debugging provider issues, developers will also want to understand how Terraform represents [complex type literals](/terraform/language/expressions/type-constraints#complex-type-literals). For example, Terraform does not provide any way to directly represent lists, maps, or sets.


### Handling Underlying Null and Unknown Values

With dynamic data, in addition to typical [null](/terraform/plugin/framework/handling-data/terraform-concepts#null-values) and [unknown](/terraform/plugin/framework/handling-data/terraform-concepts#unknown-values) value handling, provider developers will need to implement additional logic to determine if an underlying value for a dynamic is null or unknown.

#### Underlying Null

In the configuration below, Terraform knows the underlying value type, `string`, but the underlying string value is null:

```hcl
resource "examplecloud_thing" "example" {
  example_attribute = var.null_string
}

variable "null_string" {
  type    = string
  default = null
}
```

This will result in a known dynamic value, with an underlying value that is a null [string type](/terraform/plugin/framework/handling-data/types/string). This can be detected utilizing the [`(types.Dynamic).IsUnderlyingValueNull()`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/basetypes#DynamicValue.IsUnderlyingValueNull) method. An equivalent framework value to this scenario would be:

```go
dynValWithNullString := types.DynamicValue(types.StringNull())
```

#### Underlying Unknown

In the configuration below, Terraform knows the underlying value type of [`random_shuffle.result`](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/shuffle#result), a `list(string)`, but the underlying list value is unknown:

```hcl
resource "random_shuffle" "example" {
  input        = ["one", "two"]
  result_count = 2
}

resource "examplecloud_thing" "this" {
  example_attribute = random_shuffle.example.result
}
```

This will result in a known dynamic value, with an underlying value that is an unknown [list of string types](/terraform/plugin/framework/handling-data/types/list). This can be detected utilizing the [`(types.Dynamic).IsUnderlyingValueUnknown()`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/types/basetypes#DynamicValue.IsUnderlyingValueUnknown) method. An equivalent framework value to this scenario would be:

```go
dynValWithUnknownList := types.DynamicValue(types.ListUnknown(types.StringType))
```

### Understanding Type Consistency

For [managed resources](/terraform/plugin/framework/resources), Terraform core implements [data consistency rules](https://github.com/hashicorp/terraform/blob/main/docs/resource-instance-change-lifecycle.md) between configuration, plan, and state data. With [dynamic attributes](/terraform/plugin/framework/handling-data/attributes/dynamic), these consistency rules are also applied to the **type** of data.

For example, given a dynamic `example_attribute` that is computed and optional:

```go
func (r ThingResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
    resp.Schema = schema.Schema{
        Attributes: map[string]schema.Attribute{
            "example_attribute": schema.DynamicAttribute{
                Computed: true,
                Optional: true,
                // ... potentially other fields ...
            },
            // ... potentially other attributes ...
        },
    }
}
```

If a practitioner configures this resource as:

```hcl
resource "examplecloud_thing" "example" {
  # This literal expression is a tuple[string, string]
  example_attribute = ["one", "two"]
}
```

Then the exact type must be planned and stored in state during `apply` as a [tuple](/terraform/plugin/framework/handling-data/types/tuple) with two [string](/terraform/plugin/framework/handling-data/types/string) element types. If provider code attempts to store this attribute as a different type, like a [list](/terraform/plugin/framework/handling-data/types/list) of strings, even with the same data values, Terraform will produce an error during apply:

```bash
│ Error: Provider produced inconsistent result after apply
│ 
│ When applying changes to examplecloud_thing.example, provider "provider[\"TYPE\"]" produced an unexpected new value: .example_attribute: wrong final value type: tuple required.
│ 
│ This is a bug in the provider, which should be reported in the providers own issue tracker.
```

If a practitioner configures this same resource as:

```hcl
resource "examplecloud_thing" "example" {
  example_attribute = tolist(["one", "two"])
}
```

Then the exact type must be planned and stored in state during `apply` as a [list](/terraform/plugin/framework/handling-data/types/list) of strings.
