In this post, we will take a brief look at the data types that we can use in Terraform to better understand the topic of the following post – Terraform: count, for_each, and for loops.
Documentation – Type Constraints and Types and Values.
We have the following types divided into groups:
- Primitive Types:
string
: sequence of Unicode characters, plain textnumber
: numerical valuesbool
: true or false
- Complex Types:
- Collection Types:
list
: alist
is a type of structure for storing a simple collection of values of the same type, accessible by indexmap
: a key:value collection of values of the same typeset
: similar to thelist
, but without indexes and sorting
- Structural Types:
object
: to store values of different data types – a set of named attributes, each with its own data typetuple
: a sequence of elements, each with its own data type, indexed as in thelist
- Collection Types:
Contents
Primitive types
The simplest type, in which we can store only one value of a certain type.
string
An example:
variable "var_string" { type = string default = "a string" } output "string" { value = var.var_string }
The result is obvious:
... Outputs: string = "a string"
number
Similarly, but for integer values:
variable "var_number" { type = number default = 1 } output "number" { value = var.var_number }
Result:
... Outputs: number = 1
bool
Used for the Conditional Expressions:
variable "var_bool" { type = bool default = true } output "number" { value = var.var_bool ? "True" : "False" }
Result:
... Outputs: number = "True"
Or creating a resource if the condition is valid:
resource "local_file" "file" { count = var.var_bool ? 1 : 0 filename = "file.txt" content = var.var_string }
Collection Types
list
A sequence of values of the same type with indices starting from zero.
When creating a list
, you can either not specify the type (default == any
), or limit it to one specific type:
variable "var_list_any" { type = list default = ["a string", 10] } variable "var_list_string" { type = list(string) default = ["first string", "second string"] } resource "local_file" "file" { filename = "file-${var.var_list_any[1]}.txt" content = var.var_list_string[0] } output "list_any" { value = var.var_list_any } output "list_string" { value = var.var_list_string }
Result:
... Outputs: list_any = tolist([ "a string", "10", ]) list_string = tolist([ "first string", "second string", ])
And the file:
$ cat file-10.txt first string
Within a list
you can use other data types – other list
, map
etc.
At the same time, in a list
we can have different types of primitives ( string
, number
, bool
), but the same type for other types, i.e.:
variable "var_list_any" { type = list default = ["a", true, 1] } variable "var_list_lists" { type = list default = [ ["a", "b"], ["c", "d"] ] } output "list_any" { value = var.var_list_any } output "list_lists" { value = var.var_list_lists }
Result:
... Outputs: list_any = tolist([ "a", "true", "1", ]) list_lists = tolist([ [ "a", "b", ], [ "c", "d", ], ])
With the list
we can use loops, for example:
variable "var_list_any" { type = list default = ["a string", 10] } variable "var_list_string" { type = list(string) default = ["first string", "second string"] } resource "local_file" "file" { for_each = toset(var.var_list_any) filename = "file-${each.key}.txt" content = each.value } output "list_string" { value = [ for a in var.var_list_string : upper(a)] }
Result:
... Outputs: list_string = [ "FIRST STRING", "SECOND STRING", ]
And files:
$ ls -1 file-10.txt 'file-a string.txt' $ cat file-a\ string.txt a string
map
A value in the key:value form with access to the value by the key name:
variable "var_map" { type = map default = { "one" = "first", "two" = "second" } } output "map_one" { value = var.var_map["one"] } output "map_two" { value = var.var_map["two"] }
We can also display the attribute in outputs, i.e. value = var.var_map.one
.
Result:
... Outputs: map_one = "first" map_two = "second"
We can also use lookup()
to search for values in a map
by a key:
output "map_lookup" { value = lookup(var.var_map, "one", "None") }
Result:
... Outputs: map_lookup = "first" map_one = "first" map_two = "second"
Or a more complex example – choosing a number of instances by the price depending on the instance type:
variable "instance_cost" { type = map default = { "t3.medium" = "0.04USD", "t3.large" = "0.08USD", } } variable "instance_number" { type = map default = { "0.04USD" = 2, "0.08USD" = 1, } } output "instances_count" { value = lookup(var.instance_number, var.instance_cost["t3.medium"], 0) }
Result:
... Outputs: instances_count = 2
A map
can also include a list
or another map
, but all objects must be of the same type (that is, you cannot have map
with a list
in a first item, and a map
in a second):
variable "var_map_of_maps" { type = map default = { "out-map-key-1" = { "in-map-key-1" = "inner map 1 key one", "in-map-key-2" = "inner map 1 inner key two", }, "out-map-key-2" = { "in-map-key-1" = "inner map 2 key one", "in-map-key-2" = "inner map 2 key two", }, } } output "map_of_maps" { value = var.var_map_of_maps }
Result:
... Outputs: map_of_maps = tomap({ "out-map-key-1" = { "in-map-key-1" = "inner map 1 key one" "in-map-key-2" = "inner map 1 inner key two" } "out-map-key-2" = { "in-map-key-1" = "inner map 2 key one" "in-map-key-2" = "inner map 2 key two" } })
set
A sequence of values of the same or different types as in list
, but without indexes and sorting:
variable "var_set_any" { type = set(any) default = ["string", 1] } variable "var_set_string" { type = set(string) default = ["string1", "string2"] } output "set_any" { value = var.var_set_any } output "set_string" { value = var.var_set_string }
Result:
... ... Outputs: set_any = toset([ "1", "string", ]) set_string = toset([ "string1", "string2", ])
Like with list
or map
, a set
can have nested types:
variable "var_set_lists" { type = set(list(any)) default = [ ["a", "b"], ["c", "d"] ] } output "set_any" { value = var.var_set_lists }
Result:
... set_any = toset([ tolist([ "a", "b", ]), tolist([ "c", "d", ]), ])
Structural Types
object
Unlike map
and list
, object
is a structural type that can have values of various types, including several list
and map
.
Similar to Struct in C or Golang:
variable "var_object" { type = object({ name = string, id = number, data = list(string) data_map = map(any) }) default = { name = "one", id = 10, data = ["first", "second"], data_map = { "one" = "first", "two" = "second" } } } output "object" { value = var.var_object } output "object_map" { value = var.var_object.data_map }
Result:
... Outputs: object = { "data" = tolist([ "first", "second", ]) "data_map" = tomap({ "one" = "first" "two" = "second" }) "id" = 10 "name" = "one" } object_map = tomap({ "one" = "first" "two" = "second" })
tuple
Similar to the object
, but with indexes instead of key names:
variable "var_tuple" { type = tuple ([ string, number, list(string), map(any) ] ) default = [ "one", 10, ["first", "second"], { "one" = "first", "two" = "second" } ] } output "tuple" { value = var.var_tuple } output "tuple_map" { value = var.var_tuple[3] }
Result:
Outputs: tuple = [ "one", 10, tolist([ "first", "second", ]), tomap({ "one" = "first" "two" = "second" }), ] tuple_map = tomap({ "one" = "first" "two" = "second" })
In the next post, we will look at loops in Terraform.
Useful links
- Exploring Map, List, Set, and Object Datatypes in Terraform
- How to use Terraform variables
- How to Use Terraform Variables (Locals, Input, Output, Environment)