Terraform
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 to properly handle all potential practitioner configuration scenarios.
Refer to Dynamic Data - Considerations for more information.
Dynamic is a container type that can have an underlying value of any type.
By default, dynamic values from schema (configuration, plan, and state) data are represented in the framework by types.DynamicType
and its associated value storage type of types.Dynamic
. These types fully support Terraform's type system concepts that cannot be represented in Go built-in types. Framework types can be extended 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 or nested attribute type:
Schema Type | Attribute Type |
---|---|
Data Source | schema.DynamicAttribute |
Provider | schema.DynamicAttribute |
Resource | schema.DynamicAttribute |
Ephemeral Resource | schema.DynamicAttribute |
Dynamic values are not supported as the element type of a collection type or within collection attribute types.
If the dynamic value should be a value type of an object attribute type, set the AttrTypes
map value to types.DynamicType
or the appropriate custom type.
Accessing Values
Tip
Review the attribute documentation to understand how schema-based data gets mapped into accessible values, such as a types.Dynamic
in this case.
Access types.Dynamic
information via the following methods:
(types.Dynamic).IsNull() bool
: Returns true if the dynamic value is null.(types.Dynamic).IsUnderlyingValueNull() bool
: Returns true if the dynamic value is known but the underlying value is null. See the Dynamic Data section for more information about null underlying values.(types.Dynamic).IsUnknown() bool
: Returns true if the dynamic value is unknown.(types.Dynamic).IsUnderlyingValueUnknown() bool
: Returns true if the dynamic value is known but the underlying value is unknown. See the Dynamic Data section for more information about unknown underlying values.(types.Dynamic).UnderlyingValue() attr.Value
: Returns the underlying value of the dynamic container, will benil
if null or unknown.
In this example, a dynamic value is checked for being null or unknown value first, before accessing its known value:
// 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 can be used to access the type-specific methods for data handling:
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
}
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 to properly handle all potential practitioner configuration scenarios.
Refer to the Dynamic Data documentation for more information.
Setting Values
Call one of the following to create a types.Dynamic
value:
types.DynamicNull()
: A null dynamic value.types.DynamicUnknown()
: An unknown dynamic value where the final static type is not known. Usetypes.DynamicValue()
with an unknown value if the final static type is known.types.DynamicValue(attr.Value)
: A known dynamic value, with an underlying value determined by theattr.Value
input.
In this example, a known dynamic value is created, where the underlying value is a known string value:
types.DynamicValue(types.StringValue("hello world!"))
In this example, a known dynamic value is created, where the underlying value is a known object value:
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:
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. These can adjust expected provider code usage depending on their implementation.