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.
Built-In Types and Values
A collection of attribute type and attribute value implementations is available
in the
types
package.
StringType and String
Strings are a UTF-8 encoded collection of bytes.
hello = "world"
They are used by specifying the types.StringType
constant in your
tfsdk.Attribute
's Type
property, and are represented by a types.String
struct in config, state, and plan. The types.String
struct has the following
properties:
Value
contains the string's value as a Gostring
type.Null
is set totrue
when the string's value is null.Unknown
is set totrue
when the string's value is unknown.
Int64Type and Int64
Int64 are 64-bit integer values, such as 1234
.
hello = 1234
They are used by specifying the types.Int64Type
constant in your
tfsdk.Attribute
's Type
property, and are represented by a types.Int64
struct in config, state, and plan. The types.Int64
struct has the following
properties:
Value
contains the number's value as a Goint64
type.Null
is set totrue
when the number's value is null.Unknown
is set totrue
when the number's value is unknown.
For 64-bit floating point numbers, see Float64Type
and
Float64
. For generic number handling, see
NumberType
and Number64
.
Float64Type and Float64
Float64 are 64-bit floating point values, such as 1234.5
.
hello = 1234.5
They are used by specifying the types.Float64Type
constant in your
tfsdk.Attribute
's Type
property, and are represented by a types.Float64
struct in config, state, and plan. The types.Float64
struct has the following
properties:
Value
contains the number's value as a Gofloat64
type.Null
is set totrue
when the number's value is null.Unknown
is set totrue
when the number's value is unknown.
For 64-bit integer numbers, see Int64Type
and
Int64
. For generic number handling, see
NumberType
and Number64
.
NumberType and Number
Numbers are numeric values, both whole values like 12
or fractional values
like 3.14
.
hello = 123
They are used by specifying the types.NumberType
constant in your
tfsdk.Attribute
's Type
property, and are represented by a types.Number
struct in config, state, and plan. The types.Number
struct has the following
properties:
Value
contains the number's value as a Go*big.Float
type.Null
is set totrue
when the number's value is null.Unknown
is set totrue
when the number's value is unknown.
For 64-bit integer numbers, see Int64Type
and
Int64
. For 64-bit floating point numbers, see
Float64Type
and Float64
.
BoolType and Bool
Bools are boolean values that can either be true or false.
hello = true
They are used by specifying the types.BoolType
constant in your
tfsdk.Attribute
's Type
property, and are represented by a types.Bool
struct in config, state, and plan. The types.Bool
struct has the following
properties:
Value
contains the boolean's value as a Gobool
type.Null
is set totrue
when the boolean's value is null.Unknown
is set totrue
when the boolean's value is unknown.
ListType and List
Lists are ordered collections of other types. Their elements, the values inside the list, must all be of the same type.
hello = ["red", "blue", "green"]
They are used by specifying a types.ListType
value in your
tfsdk.Attribute
's Type
property. You must specify an ElemType
property
for your list, indicating what type the elements should be. Lists are
represented by a types.List
struct in config, state, and plan. The
types.List
struct has the following properties:
ElemType
will always contain the same type as theElemType
property of thetypes.ListType
that created thetypes.List
.Elem
contains a list of values, one for each element in the list. The values will all be of the value type produced by theElemType
for the list.Null
is set totrue
when the entire list's value is null. Individual elements may still be null even if the list'sNull
property isfalse
.Unknown
is set totrue
when the entire list's value is unknown. Individual elements may still be unknown even if the list'sUnknown
property isfalse
.
Elements of a types.List
with a non-null, non-unknown value can be accessed
without using type assertions by using the types.List
's ElementsAs
method,
which uses the same conversion rules as the Get
methods described in Access
State, Config, and Plan.
For an unordered collection with uniqueness constraints, see SetType
and
Set
.
MapType and Map
Maps are unordered collections of other types with unique string indexes. Their elements, the values inside the map, must all be of the same type. The keys used to index the elements must be strings, but there are (theoretically) no limitations on what keys are acceptable or how many there can be.
hello = {
pi = 3.14
random = 4
"meaning of life" = 42
}
They are used by specifying a types.MapType
value in your
tfsdk.Attribute
's Type
property. You must specify an ElemType
property
for your map, indicating what type the elements should be. Maps are
represented by a types.Map
struct in config, state, and plan. The
types.Map
struct has the following properties:
ElemType
will always contain the same type as theElemType
property of thetypes.MapType
that created thetypes.Map
.Elem
contains a map of values, one for each element in the map. The keys will be the keys defined in the config, state, or plan, and the values will all be of the value type produced by theElemType
for the map.Null
is set totrue
when the entire map's value is null. Individual elements may still be null even if the map'sNull
property isfalse
.Unknown
is set totrue
when the entire map's value is unknown. Individual elements may still be unknown even if the map'sUnknown
property isfalse
.
Elements of a types.Map
with a non-null, non-unknown value can be accessed
without using type assertions by using the types.Map
's ElementsAs
method,
which uses the same conversion rules as the Get
methods described in Access
State, Config, and Plan.
ObjectType and Object
Objects are unordered collections of other types with unique, pre-specified
attributes. The attributes have names represented by strings, and each
attribute can specify its own type, similar to a Go struct
type. The
attributes and their types are considered part of the object's type; two
objects are not the same type unless they have the same attributes, and those
attributes have the same types.
hello = {
pi = 3.14
demo = true
color = "red"
}
They are used by specifying a types.ObjectType
value in your
tfsdk.Attribute
's Type
property. You must specify an AttrTypes
property
for your object, indicating a map of the attribute names and the types of those
attributes. Objects are represented by a types.Object
struct in config,
state, and plan. The types.Object
struct has the following properties:
AttrTypes
will always contain the same attribute names and associated types as theAttrTypes
property of thetypes.ObjectType
that created thetypes.Object
.Attrs
contains a map of attribute names to values. Each attribute is guaranteed to always be present in the map. The values will always be of the value type for that attribute in theAttrTypes
of the object.Null
is set totrue
when the entire object's value is null. Individual attributes may still be null even if the object'sNull
property is false.Unknown
is set totrue
when the entire object's value is unknown. Individual attributes may still be unknown even if the object'sUnknown
property isfalse
.
A non-null, non-unknown types.Object
value can be converted to a Go struct
without using type assertions by using the types.Object
's As
method,
which uses the same conversion rules as the Get
methods described in Access
State, Config, and Plan.
SetType and Set
Sets are unordered collections of other types. Their elements, the values inside the set, must all be of the same type and must be unique.
hello = ["red", "blue", "green"]
They are used by specifying a types.SetType
value in your
tfsdk.Attribute
's Type
property. You must specify an ElemType
property
for your set, indicating what type the elements should be. Sets are
represented by a types.Set
struct in config, state, and plan. The
types.Set
struct has the following properties:
ElemType
will always contain the same type as theElemType
property of thetypes.SetType
that created thetypes.Set
.Elem
contains a list of values, one for each element in the set. The values will all be of the value type produced by theElemType
for the list. Each element must be unique.Null
is set totrue
when the entire set's value is null. Individual elements may still be null even if the set'sNull
property isfalse
.Unknown
is set totrue
when the entire set's value is unknown. Individual elements may still be unknown even if the set'sUnknown
property isfalse
.
Elements of a types.Set
with a non-null, non-unknown value can be accessed
without using type assertions by using the types.Set
's ElementsAs
method,
which uses the same conversion rules as the Get
methods described in Access
State, Config, and Plan.
For an ordered collection without uniqueness constraints, see ListType
and
List
.
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.
Important: Specifying plan customization for attribute types is not yet supported, limiting their utility. Support is expected in the near future.
attr.Type
Interface
Use the attr.Type
interface
to implement an attribute type. It tells Terraform about its constraints and tells the framework how to create new attribute values from the information Terraform supplies. attr.Type
has the following methods.
Method | Description |
---|---|
TerraformType | Returns the tftypes.Type value that describes its type constraints. This is how Terraform will know what type of values it can accept. |
ValueFromTerraform | Returns an attribute value from the tftypes.Value that Terraform supplies, or to return an error if it cannot. This error should not be used for validation purposes, and is expected to indicate programmer error, not practitioner error. |
Equal | Returns true if the attribute type is considered equal to the passed attribute type. |
AttributePathStepper
Interface
All attribute types must implement the tftypes.AttributePathStepper
interface,
so the framework can access element or attribute types using attribute paths.
xattr.TypeWithValidation
Interface
If validation for type values is desired, use the xattr.TypeWithValidation
interface to include validation logic for type values. The framework will call this functionality when validating all values based on the schema.
Method | Description |
---|---|
Validate | Returns any warning or error diagnostics for the given value. |
Type-Specific Interfaces
Case | Interface | Description |
---|---|---|
Elements of the same type | TypeWithElementType | Attribute types that contain elements of the same type, like maps and lists, are required to implement attr.TypeWithElementType , which adds WithElementType and ElementType methods to the attr.Type interface. WithElementType must return a copy of the attribute type, but with its element type set to the passed type. ElementType must return the attribute type's element type. |
Elements of different types | TypeWithElementTypes | Attribute types that contain elements of differing types, like tuples, are required to implement the attr.TypeWithElementTypes , which adds WithElementTypes and ElementTypes methods to the attr.Type interface. WithElementTypes must return a copy of the attribute type, but with its element types set to the passed element types. ElementTypes must return the attribute type's element types. |
Contain attributes | TypeWithAttributeTypes | Attribute types that contain attributes, like objects, are required to implement the attr.TypeWithAttributeTypes interface, which adds WithAttributeTypes and AttributeTypes methods to the attr.Type interface. WithAttributeTypes must return a copy of the attribute type, but with its attribute types set to the passed attribute types. AttributeTypes must return the attribute type's attribute types. |
attr.Value
Interface
Use the attr.Value
interface
to implement an attribute value. It tells the framework how to express that
attribute value in a way that Terraform will understand. attr.Value
has the
following methods.
Method | Description |
---|---|
ToTerraformValue | Returns a Go type that is valid input for tftypes.NewValue for the tftypes.Type specified by the attr.Type that creates the attr.Value . |
Equal | Returns true if the passed attribute value should be considered to the attribute value the method is being called on. The passed attribute value is not guaranteed to be of the same Go type. |