Variables in Terraform¶
Terraform uses Hashicorp Language (HCL). HCL supports the use of variables.
Terraform variables are essentially placeholders for values that you can set in order to further customize configurations to make them more reusable and dynamic.
Supported Data Types¶
Variables in HCL (Hashicorp Language) support multiple different data types.
The data types as specified by HCL:
string: Array of characters.number: Numeric values.- Referenced as
int/floatin provider documentation.
- Referenced as
bool: True/false values.list: Array (single vector).map: Associative array or dictionary, stores key/value pairs.tuple: Immutable single-vector array.object: JSON-like data type that can store any number of other data types (maps, lists, etc.) and nest them.set: A list of unique values.
Locals¶
Local variables can be declared using a locals block, typically at the top of
the file. This block is a group of key/value pairs that can be referenced
inside the file it's defined in.
locals {
name = "new-vm"
os_type = "ubuntu"
cpu_type = "x86-64-v2-AES"
memory = 2048
cpu_cores = 1
cpu_sockets = 1
tags = {
name = "test-vm"
env = "dev"
}
storage = "vmdata"
}
These variables can then be referenced in the rest of main.tf by using the local keyword,
then using dot notation to select the specific variable (e.g., local.name)
Input Variables¶
Input variables are used to pass in values from outside the config/module.
They're used to assign dynamic values to resource attributes. The difference
between locals and input vars is the input vars allow you to pass values
before code execution.
Input variables are meant to act as inputs to modules. Input variables declared within modules are used to accept outside values.
When declaring input variables, we can set attributes:
type: Data typedefault: Default value if none is given-
description: A description for the var, used to generate documentation for the module -
validation: Defines validation rulesconditionerror_message
-
sensitive: Boolean used to mask the variable's value anywhere it would be displayed (e.g., for API keys) -
ephemeral: Available during runtime, but not stored instateorplanfiles.- Good for temporary variables (short-lived tokens, session IDs, etc.).
We typically set these in a separate variables.tf file.
The basic syntax is:
variable "<label>" {
description = "An example variable block"
type = "<type>"
default = "<default value>"
sensitive = true # or false
}
The values of the variables can be accessed in main.tf (or other) by using
the var keyword with dot notation, using the <label> as the name of the
variable.
So for this example:
variable "testvar" {
description = "Test variable"
type = string
default = "Hello, world"
}
main.tf as follows:
If we are using a data type that stores multiple values, we need to specify the type for each value.
For the list type, we'd need to specify the list item's attributes.
Same with object types, map types, set types, and tuple types.
variable "example_list" {
description = "An example list variable in a variable block"
type = list(string)
default = "<default value>"
sensitive = true # or false
}
variable "example_object" {
description = "An example object variable in a variable block"
type = object({
name = string
age = number
enabled = bool
tags = list(string)
})
default = {
name = "john"
age = 30
enabled = true
tags = ["engineer", "male", 30]
}
sensitive = true # or false
}
variable "example_tuple" {
description = "An example tuple variable in a variable block"
type = tuple([string, number, bool])
default = ["item1", 33, false]
}
variable "example_set" {
description = "An example set variable in a variable block"
type = set(string)
default = ["item1", "item2", "item3"]
}
variable "example_map" {
description = "An example map variable in a variable block"
type = map(string)
default = {
key1 = "value1"
key2 = "value2"
}
}
Complex Input Variables¶
We can even use a map of objects or list of objects when declaring input variables.
These ones have a bit more complexity involved, but they're powerful.
variable "example_object_map" {
description = "An example map of objects in a variable block"
type = map(object({
key1 = string
key2 = string
}))
default = {
"vm1" = {
key1 = "value1"
key2 = "value2"
},
"vm2" = {
key1 = "value1"
key2 = "value2"
},
"vm3" = {
key1 = "value1"
key2 = "value2"
}
}
}
# Note we're doing `map()`, then `object()` nested within.
# The `map` objects `vm1`/`vm2` have quotes, but the object keys themselves do not.
# Also note the commas between map items.
variable "example_object_list" {
description = "An example list of objects in a variable block"
type = list(object({
key1 = string
key2 = string
}))
default = [
{
key1 = "value1"
key2 = "value2"
},
{
key1 = "value1"
key2 = "value2"
},
{
key1 = "value1"
key2 = "value2"
}
]
}
Variable Validation¶
We can specify conditions that must be met for a variable's value to be valid.
Within the variable block, we'd specify the validation keyword, along with
some code to be executed to test the value.
variable "name" {
description = "The name of a VM or something"
type = string
default = "new-vm"
validation = {
condition = length(var.name) > 1
error_message = "We need at least 2 characters for the name!"
}
}
Environment Variables¶
Input variable values can be set by using Terraform environment variables.
All we need to do in order to pass environment variables to Terraform is to
prepend the variable's name with TF_VAR_<name>.
When setting variables this way, the <name> needs to match the variables
declared in variables.tf.
variables.tf..tfvars¶
Any file with the .tfvars file extension (or simply .tfvars by itself) will
be used to define values for the variables declared inside variables.tf.
The syntax will be the same as other HCL variable definitions.
For example, a terraform.tfvars file with the following definition:
Will populate the variable defined inside variables.tf: