Skip to main content

Splat Expressions

A splat expression provides a more concise way to express a common operation that could otherwise be performed with a for expression.

If var.list is a list of objects that all have an attribute id, then a list of the ids could be produced with the following for expression:

[for o in var.list : o.id]

This is equivalent to the following splat expression:

var.list[*].id

The special [*] symbol iterates over all of the elements of the list given to its left and accesses from each one the attribute name given on its right. A splat expression can also be used to access attributes and indexes from lists of complex types by extending the sequence of operations to the right of the symbol:

var.list[*].interfaces[0].name

The above expression is equivalent to the following for expression:

[for o in var.list : o.interfaces[0].name]

Splat Expressions with Maps

The splat expression patterns shown above apply only to lists, sets, and tuples. To get a similar result with a map or object value you must use for expressions.

Resources that use the for_each argument will appear in expressions as a map of objects, so you can't use splat expressions with those resources. For more information, see Referring to Resource Instances.

Single Values as Lists

Splat expressions have a special behavior when you apply them to a value that isn't a list, set, or tuple.

If the value is anything other than a null value then the splat expression will transform it into a single-element list, or more accurately a single-element tuple value. If the value is null then the splat expression will return an empty tuple.

This special behavior can be useful for modules that accept optional input variables whose default value is null to represent the absence of any value. This allows the module to adapt the variable value for OpenTF language features designed to work with collections. For example:

variable "website_setting" {
type = object({
index_document = string
error_document = string
})
default = null
}

resource "aws_s3_bucket" "example" {
# ...

dynamic "website" {
for_each = var.website_setting[*]
content {
index_document = website.value.index_document
error_document = website.value.error_document
}
}
}

The above example uses a dynamic block, which generates zero or more nested blocks based on a collection value. The input variable var.website_setting is defined as a single object that might be null, so the dynamic block's for_each expression uses [*] to ensure that there will be one block if the module caller sets the website argument, or zero blocks if the caller leaves it set to null.

This special behavior of splat expressions is not obvious to an unfamiliar reader, so we recommend using it only in for_each arguments and similar situations where the context implies working with a collection. Otherwise, the meaning of the expression may be unclear to future readers.

Legacy (Attribute-only) Splat Expressions

Earlier versions of the OpenTF language had a slightly different version of splat expressions, which OpenTF continues to support for backward compatibility. This older variant is less useful than the modern form described above, and so we recommend against using it in new configurations.

The legacy "attribute-only" splat expressions use the sequence .*, instead of [*]:

var.list.*.interfaces[0].name

This form has a subtly different behavior, equivalent to the following for expression:

[for o in var.list : o.interfaces][0].name

Notice that with the attribute-only splat expression the index operation [0] is applied to the result of the iteration, rather than as part of the iteration itself. Only the attribute lookups apply to each element of the input. This limitation was confusing some people using older versions of OpenTF and so we recommend always using the new-style splat expressions, with [*], to get the more consistent behavior.