Terraform
- Plugin Framework
- v1.16.x (latest)
- No versions of this document exist before v1.15.x. Click below to redirect to the version homepage.
- v1.15.x
- v1.14.x
- v1.13.x
- v1.12.x
- v1.11.x
- v1.10.x
- v1.9.x
- v1.8.x
- v1.7.x
- v1.6.x
- v1.5.x
- v1.3.x
- v1.2.x
- v1.1.x
- v1.0.x
- v0.17.x
- v0.16.x
- v0.15.x
- v0.14.x
- v0.13.x
- v0.12.x
- v0.11.x
- v0.10.x
- v0.9.x
- v0.8.x
- v0.7.x
Object Type
Object types store a mapping of explicit attribute names to value types. Objects must declare all attribute values, even when null or unknown, unless the entire object is null or unknown.
By default, objects from schema (configuration, plan, and state) data are represented in the framework by types.ObjectType and its associated value storage type of types.Object. These types fully support Terraform's type system concepts that cannot be represented in Go built-in types, such as a struct. 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 single structure of a nested attributes to a schema or nested attribute type:
If a wrapping collection is needed on the structure of nested attributes, any of the other nested attribute and nested block types can be used.
Use one of the following attribute types to directly add an object value directly to a schema or nested attribute type:
| Schema Type | Attribute Type |
|---|---|
| Data Source | schema.ObjectAttribute |
| Provider | schema.ObjectAttribute |
| Resource | schema.ObjectAttribute |
If the object value should be the element type of another collection attribute type, set the ElementType field to types.ObjectType{AttrTypes: /* ... */} or the appropriate custom type.
If the object value should be a value type of an object attribute type, set the AttributeTypes map value to types.ObjectType{AttrTypes: /* ... */} or the appropriate custom type.
Accessing Values
Access types.Object information via the following methods:
(types.Object).IsNull() bool: Returnstrueif the object is null.(types.Object).IsUnknown() bool: Returnstrueif the object is unknown.(types.Object).Attributes() map[string]attr.Value: Returns the knownmap[string]attr.Valuevalue, ornilif null or unknown.(types.Object).As(context.Context, any, ObjectAsOptions) diag.Diagnostics: Converts the known values into the given Go type, if possible. It is recommended to use a struct of framework types to account for attributes which may be unknown.
In this example, an object with a string attribute is checked for being null or unknown value first, before accessing its known value attributes as a Go struct type:
// Example data model definitions
// type ExampleModel struct {
// ExampleAttribute types.Object `tfsdk:"example_attribute"`
// }
//
// type ExampleAttributeModel struct {
// StringAttribute types.String `tfsdk:"string_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() {
// ...
}
var exampleAttribute ExampleAttributeModel
diags := data.ExampleAttribute.As(ctx, &exampleAttribute, basetypes.ObjectAsOptions{})
// Object data now is accessible, such as: exampleAttribute.StringAttribute.StringValue()
Setting Values
Call one of the following to create a types.Object value:
types.ObjectNull(map[string]attr.Type) types.Object: A null object value with the given element type.types.ObjectUnknown(map[string]attr.Type) types.Object: An unknown object value with the given element type.types.ObjectValue(map[string]attr.Type, map[string]attr.Value) (types.Object, diag.Diagnostics): A known value with the given attribute type mapping and attribute values mapping.types.ObjectValueFrom(context.Context, map[string]attr.Type, any) (types.Object, diag.Diagnostics): A known value with the given attribute type mapping and values. This can convert the source data from standard Go types into framework types as noted in the documentation for each type, such as giving astructfor atypes.Object.types.ObjectValueMust(map[string]attr.Type, map[string]attr.Value) types.Object: A known value with the given attribute type mapping and attribute value mapping. Any diagnostics are converted to a runtime panic. This is recommended only for testing or exhaustively tested logic.
In this example, a known object value is created from framework types:
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)
Otherwise, for certain framework functionality that does not require types implementations directly, such as:
(tfsdk.State).SetAttribute()types.ListValueFrom()types.MapValueFrom()types.ObjectValueFrom()types.SetValueFrom()
Objects can be automatically converted to any Go struct type that follows these constraints to prevent accidental data loss:
- Every struct type must be an acceptable conversion type according to the type documentation, such as
*stringbeing acceptable for a string type. However, it is recommended to use framework types to simplify data modeling (one model type for accessing and setting data) and prevent errors when encountering unknown values from Terraform. - Every struct field must have a
tfsdkstruct tag and every attribute in the object must have a corresponding struct tag. Thetfsdkstruct tag must name an attribute in the object that it is being mapped or be set to-to explicitly declare it does not map to an attribute in the object.
In this example, a struct is directly used to set an object attribute value:
type ExampleAttributeModel struct {
Int64Attribute types.Int64 `tfsdk:"int64_attribute`
StringAttribute types.String `tfsdk:"string_attribute"`
}
value := ExampleAttributeModel{
Int64Attribute: types.Int64Value(123),
StringAttribute: types.StringValue("example"),
}
diags := resp.State.SetAttribute(ctx, path.Root("example_attribute"), value)
In this example, a types.Object is created from a struct:
type ExampleAttributeModel struct {
Int64Attribute types.Int64 `tfsdk:"int64_attribute`
StringAttribute types.String `tfsdk:"string_attribute"`
}
func (m ExampleAttributeModel) AttributeTypes() map[string]attr.Type {
return map[string]attr.Type{
"int64_attribute": types.Int64Type,
"string_attribute": types.StringType,
}
}
value := ExampleAttributeModel{
Int64Attribute: types.Int64Value(123),
StringAttribute: types.StringValue("example"),
}
objectValue, diags := types.ObjectValueFrom(ctx, value.AttributeTypes(), value)
Extending
The framework supports extending its base type implementations with custom types. These can adjust expected provider code usage depending on their implementation.