Terraform
Attribute Types
Attributes are the fields in a resource, data source, or provider. They hold the values that end up in state. Every attribute has an attribute type, which describes the constraints on the data the attribute can hold. When you access an attribute from the configuration, state, or plan, you are accessing attribute values, which are the actual data that was found in the configuration, state, or plan.
You can either use the built-in attribute type and value implementations or implement your own.
Null and Unknown Values
There are two values every attribute in Terraform can hold, regardless of their type: null and unknown.
Null
Null represents the absence of a Terraform value. It is usually encountered with optional attributes that the practitioner neglected to specify a value for, but can show up on any non-required attribute. Required attributes can never be null.
Unknown
Unknown represents a Terraform value that is not yet known. Terraform uses a graph of providers, resources, and data sources to do things in the right order, and when a provider, resource, or data source relies on a value from another provider, resource, or data source that has not been resolved yet, it represents that state by using the unknown value. For example:
resource "example_foo" "bar" {
hello = "world"
demo = true
}
resource "example_baz" "quux" {
foo_id = example_foo.bar.id
}
In the example above, example_baz.quux
is relying on the id
attribute of
example_foo.bar
. The id
attribute of example_foo.bar
isn't known until
after the apply. The plan would list it as (known after apply)
. During the
plan phase, example_baz.quux
would get an unknown value as the value for
foo_id
.
Because they can result from interpolations in the practitioner's config, you have no control over what attributes may contain an unknown value. However, by the time a resource is expected to be created, read, updated, or deleted, only its computed attributes can be unknown. The rest are guaranteed to have known values (or be null).
Provider configuration values can be unknown, and providers should handle that situation, even if that means just returning an error.
Framework Attribute Types
The framework provides a standard set of schema attribute types that are based on the framework type system available in the types
package. These types bridge the implementation details between Terraform's type system and Go code in providers. The framework attribute types also support provider-defined types via a CustomType
field. Refer to Custom Types for more information about implementing provider-defined types.
Terraform Type | Framework Attribute Type | Framework Value Type | Known Value Go Type | Use Case |
---|---|---|---|---|
bool | schema.BoolAttribute | types.Bool | bool | Boolean true or false |
number | schema.Float64Attribute | types.Float64 | float64 | 64-bit floating point number |
number | schema.Int64Attribute | types.Int64 | int64 | 64-bit integer |
list | schema.ListAttribute | types.List | []attr.Value | Ordered collection of single element type |
map | schema.MapAttribute | types.Map | map[string]attr.Value | Mapping of string keys to single element type |
number | schema.NumberAttribute | types.Number | *big.Float | Large floating point or number |
object | schema.ObjectAttribute | types.Object | map[string]attr.Value | Structure mapping string attibute keys to any value type |
set | schema.SetAttribute | types.Set | []attr.Value | Unordered, unique collection of single element type |
string | schema.StringAttribute | types.String | string | Collection of UTF-8 encoded characters |
String
Strings are a UTF-8 encoded collection of bytes.
Given an example Terraform configuration that sets a string value to the example_attribute
attribute:
example_attribute = "terraform"
The associated schema type is schema.StringAttribute
:
"example_attribute": schema.StringAttribute{
// ... other fields ...
}
The associated framework type is types.StringType
and value type is types.String
in configuration, plan, and state data.
Access types.String
information via the following methods:
(types.String).IsNull() bool
: Returns true if the string is null.(types.String).IsUnknown() bool
: Returns true if the string is unknown.(types.String).ValueString() string
: Returns the known string, or an empty string if null or unknown.
The (types.String).String()
method is reserved for debugging purposes and returns "<null>"
if the value is null and "<unknown>"
if the value is unknown. Use (types.String).ValueString()
for any Terraform data handling.
Call one of the following to create a types.String
:
types.StringNull()
: A null string value.types.StringUnknown()
: An unknown string value.types.StringValue(string)
: A known value.
Int64
Int64 are 64-bit integer values, such as 1234
. For 64-bit floating point numbers, use Float64
. For generic number handling, use Number
.
Given an example Terraform configuration that sets an integer value to the example_attribute
attribute:
example_attribute = 1234
The associated schema type is schema.Int64Attribute
:
"example_attribute": schema.Int64Attribute{
// ... other fields ...
}
The associated framework type is types.Int64Type
and value type is types.Int64
in configuration, plan, and state data.
Access types.Int64
information via the following methods:
(types.Int64).IsNull() bool
: Returns true if the integer is null.(types.Int64).IsUnknown() bool
: Returns true if the integer is unknown.(types.Int64).ValueInt64() int64
: Returns the knownint64
value, or0
if null or unknown.
Call one of the following to create a types.Int64
:
types.Int64Null()
: A null integer value.types.Int64Unknown()
: An unknown integer value.types.Int64Value(int64)
: A known value.
Float64
Float64 are 64-bit floating point values, such as 1234.5
. For 64-bit integer numbers, use Int64
. For generic number handling, use Number
.
Given an example Terraform configuration that sets a floating point value to the example_attribute
attribute:
example_attribute = 1234.5
The associated schema type is schema.Float64Attribute
:
"example_attribute": schema.Float64Attribute{
// ... other fields ...
}
The associated framework type is types.Float64Type
and value type is types.Float64
in configuration, plan, and state data.
Access types.Float64
information via the following methods:
(types.Float64).IsNull() bool
: Returns true if the number is null.(types.Float64).IsUnknown() bool
: Returns true if the number is unknown.(types.Float64).ValueFloat64() float64
: Returns the knownfloat64
value, or0.0
if null or unknown.
Call one of the following to create a types.Float64
:
types.Float64Null()
: A null number value.types.Float64Unknown()
: An unknown number value.types.Float64Value(float64)
: A known value.
Number
Numbers are numeric values, both whole values like 12
or fractional values like 3.14
. Use this type for exceptionally large numbers. For 64-bit integer numbers, use Int64
. For 64-bit floating point numbers, use Float64
.
Given an example Terraform configuration that sets a number value to the example_attribute
attribute:
example_attribute = 123
The associated schema type is schema.NumberAttribute
:
"example_attribute": schema.NumberAttribute{
// ... other fields ...
}
The associated framework type is types.NumberType
and value type is types.Number
in configuration, plan, and state data.
Access types.Number
information via the following methods:
(types.Number).IsNull() bool
: Returns true if the number is null.(types.Number).IsUnknown() bool
: Returns true if the number is unknown.(types.Number).ValueBigFloat() *big.Float
: Returns the known*big.Float
value, ornil
if null or unknown.
Call one of the following to create a types.Number
:
types.NumberNull()
: A null number value.types.NumberUnknown()
: An unknown number value.types.NumberValue(*big.Float)
: A known value.
Bool
Bools are boolean values that can either be true or false.
Given an example Terraform configuration that sets a boolean value to the example_attribute
attribute:
example_attribute = true
The associated schema type is schema.BoolAttribute
:
"example_attribute": schema.BoolAttribute{
// ... other fields ...
}
The associated framework type is types.BoolType
and value type is types.Bool
in configuration, plan, and state data.
Access types.Bool
information via the following methods:
(types.Bool).IsNull() bool
: Returns true if the boolean is null.(types.Bool).IsUnknown() bool
: Returns true if the boolean is unknown.(types.Bool).ValueBool() bool
: Returns the knownbool
value, orfalse
if null or unknown.
Call one of the following to create a types.Bool
:
types.BoolNull()
: A null boolean value.types.BoolUnknown()
: An unknown boolean value.types.BoolValue(bool)
: A known value.
List
Lists are ordered collections of a single element type.
Use List Nested Attributes for lists of objects that need additional schema information. Use Set for unordered collections.
Given an example Terraform configuration that sets a list of string values to the example_attribute
attribute:
example_attribute = ["red", "blue", "green"]
The associated schema type is schema.ListAttribute
:
"example_attribute": schema.ListAttribute{
ElementType: types.StringType,
// ... other fields ...
}
The associated framework type is types.ListType
and value type is types.List
in configuration, plan, and state data.
Access types.List
information via the following methods:
(types.List).IsNull() bool
: Returns true if the list is null.(types.List).IsUnknown() bool
: Returns true if the list is unknown. Returns false if the number of elements is known, any of which may be unknown.(types.List).Elements() []attr.Value
: Returns the known[]attr.Value
value, ornil
if null or unknown.(types.List).ElementsAs(context.Context, any, bool) diag.Diagnostics
: Converts the known values into the given Go type, if possible, using the conversion rules.
Call one of the following to create a types.List
:
types.ListNull(attr.Type) types.List
: A null list value with the given element type.types.ListUnknown(attr.Type) types.List
: An unknown list value with the given element type.types.ListValue(attr.Type, []attr.Value) (types.List, diag.Diagnostics)
: A known value with the given element type and values.types.ListValueFrom(context.Context, attr.Type, any) (types.List, diag.Diagnostics)
: A known value with the given element type and values. Can convert from standard Go types, using the conversion rules.types.ListValueMust(map[string]attr.Type, map[string]attr.Value) types.List
: A known value with the given element type and values. Any diagnostics are converted to a runtime panic. This is recommended only for testing or exhaustively tested logic.
Map
Maps are mappings of string keys to values of a single element type.
Use Map Nested Attributes for maps of objects that need additional schema information. Use Object for structures of string attribute names to any value.
Given an example Terraform configuration that sets a map of string values to the example_attribute
attribute:
example_attribute = {
red = "fire",
blue = "sky",
green = "plant",
}
The associated schema type is schema.MapAttribute
:
"example_attribute": schema.MapAttribute{
ElementType: types.StringType,
// ... other fields ...
}
The associated framework type is types.MapType
and value type is types.Map
in configuration, plan, and state data.
Access types.Map
information via the following methods:
(types.Map).IsNull() bool
: Returns true if the map is null.(types.Map).IsUnknown() bool
: Returns true if the map is unknown. Returns false if the number of elements is known, any of which may be unknown.(types.Map).Elements() map[string]attr.Value
: Returns the knownmap[string]attr.Value
value, ornil
if null or unknown.(types.Map).ElementsAs(context.Context, any, bool) diag.Diagnostics
: Converts the known values into the given Go type, if possible, using the conversion rules.
Call one of the following to create a types.Map
:
types.MapNull(attr.Type)
: A null map value with the given element type.types.MapUnknown(attr.Type)
: An unknown map value with the given element type.types.MapValue(attr.Type, map[string]attr.Value) (types.Map, diag.Diagnostics)
: A known value with the given element type and values.types.MapValueFrom(context.Context, attr.Type, any) (types.Map, diag.Diagnostics)
: A known value with the given element type and values. Can convert from standard Go types, using the conversion rules.types.MapValueMust(map[string]attr.Type, map[string]attr.Value) types.Map
: A known value with the given element type and values. Any diagnostics are converted to a runtime panic. This is recommended only for testing or exhaustively tested logic.
Object
Objects are mappings of string attribute names to values of any type. Objects must always declare all attribute values, even when those attributes are null or unknown, unless the entire object is null or unknown.
Use Single Nested Attributes for objects that need additional schema information. Use Map for mappings of string keys to a single element type.
Given an example Terraform configuration that sets a map of string values to the example_attribute
attribute:
example_attribute = {
pi = 3.14
demo = true
color = "red"
}
The associated schema type is schema.ObjectAttribute
:
"example_attribute": schema.ObjectAttribute{
AttributeTypes: map[string]attr.Type{
"pi": types.Float64Type,
"demo": types.BoolType,
"color": types.StringType,
},
// ... other fields ...
}
The associated framework type is types.ObjectType
and value type is types.Object
in configuration, plan, and state data.
Access types.Object
information via the following methods:
(types.Object).IsNull() bool
: Returns true if the object is null.(types.Object).IsUnknown() bool
: Returns true if the object is unknown. Returns false if the number of elements is known, any of which may be unknown.(types.Object).Attributes() map[string]attr.Value
: Returns the knownmap[string]attr.Value
value, ornil
if null or unknown.(types.Object).As(context.Context, any, ObjectAsOptions) diag.Diagnostics
: Converts the known values into the given Go type, if possible, using the conversion rules.
Call one of the following to create a types.Object
:
types.ObjectNull(map[string]attr.Type) types.Object
: A null object value with the given attribute type mapping.types.ObjectUnknown(map[string]attr.Type) types.Object
: An unknown object value with the given attribute type mapping.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 value mapping.types.ObjectValueFrom(context.Context, attr.Type, any) (types.Object, diag.Diagnostics)
: A known value with the given attribute type mapping and values. Can convert from standard Go types, using the conversion rules.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.
Set
Set are unordered, unique collections of a single element type.
Use Set Nested Attributes for sets of objects that need additional schema information. Use List for ordered collections.
Given an example Terraform configuration that sets a set of string values to the example_attribute
attribute:
example_attribute = ["red", "blue", "green"]
The associated schema type is schema.SetAttribute
:
"example_attribute": schema.SetAttribute{
ElementType: types.StringType,
// ... other fields ...
}
The associated framework type is types.SetType
and value type is types.Set
in configuration, plan, and state data.
Access types.Set
information via the following methods:
(types.Set).IsNull() bool
: Returns true if the list is null.(types.Set).IsUnknown() bool
: Returns true if the list is unknown. Returns false if the number of elements is known, any of which may be unknown.(types.Set).Elements() []attr.Value
: Returns the known[]attr.Value
value, ornil
if null or unknown.(types.Set).ElementsAs(context.Context, any, bool) diag.Diagnostics
: Converts the known values into the given Go type, if possible, using the conversion rules.
Call one of the following to create a types.Set
:
types.SetNull(attr.Type) types.Set
: A null list value with the given element type.types.SetUnknown(attr.Type) types.Set
: An unknown list value with the given element type.types.SetValue(attr.Type, []attr.Value) (types.Set, diag.Diagnostics)
: A known value with the given element type and values.types.SetValueFrom(context.Context, attr.Type, any) (types.Set, diag.Diagnostics)
: A known value with the given element type and values. Can convert from standard Go types, using the conversion rules.types.SetValueMust(map[string]attr.Type, map[string]attr.Value) types.Set
: A known value with the given element type and values. Any diagnostics are converted to a runtime panic. This is recommended only for testing or exhaustively tested logic.
Nested Attributes
Only supported when using protocol version 6.
Nested attributes enable provider developers to define objects of attributes which fully support attribute behaviors and practitioners to configure these directly using expressions.
SingleNestedAttribute
With single nested attributes, the attribute behaves like an object. The practitioner can only specify one definition of the nested attributes.
resource "example_foo" "bar" {
nested_attribute = {
hello = "world"
demo = true
}
}
func (e *exampleResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"nested_attribute": schema.SingleNestedAttribute{
/* ... */
Attributes: map[string]schema.Attribute{
"hello": schema.StringAttribute{
/* ... */
},
"demo": schema.BoolAttribute{
/* ... */
},
},
},
},
}
}
ListNestedAttribute
With list nested attributes, the attribute behaves like a list of objects. The practitioner can specify any number of groups of these attributes.
resource "example_foo" "bar" {
nested_attribute = [
{
hello = "world"
demo = true
},
{
hello = "moon"
demo = false
},
]
}
func (e *exampleResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"nested_attribute": schema.ListNestedAttribute{
/* ... */
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"hello": schema.StringAttribute{
/* ... */
},
"demo": schema.BoolAttribute{
/* ... */
},
},
},
},
},
}
}
MapNestedAttribute
With map nested attributes, the attribute behaves like a map of objects. The practitioner can specify any number of groups of these attributes, with string keys associated with each group.
resource "example_foo" "bar" {
nested_attribute = {
"red" = {
hello = "world"
demo = true
},
"blue" = {
hello = "moon"
demo = false
},
}
}
func (e *exampleResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"nested_attribute": schema.MapNestedAttribute{
/* ... */
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"hello": schema.StringAttribute{
/* ... */
},
"demo": schema.BoolAttribute{
/* ... */
},
},
},
},
},
}
}
SetNestedAttribute
With set nested attributes, the attributes behave like a set of objects. The practitioner can specify any number of groups of these attributes.
resource "example_foo" "bar" {
nested_attribute = [
{
hello = "world"
demo = true
},
{
hello = "moon"
demo = false
},
]
}
func (e *exampleResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"nested_attribute": schema.SetNestedAttribute{
Optional: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"hello": schema.StringAttribute{
/* ... */
},
"demo": schema.BoolAttribute{
/* ... */
},
},
},
},
},
}
}
Create Provider-Defined Types and Values
You may want to build your own attribute value and type implementations to allow your provider to combine validation, description, and plan customization behaviors into a reusable bundle. This helps avoid duplication or reimplementation and ensures consistency.
Refer to Custom Types for further details on creating provider-defined types and values.