- The OpenTofu Language
- Variables and Outputs
- Input Variables
Input Variables
Input variables let you customize aspects of modules without altering the module's own source code. This functionality allows you to share modules across different OpenTofu configurations, making your module composable and reusable.
When you declare variables in the root module of your configuration, you can
set their values using CLI options and environment variables.
When you declare them in child modules,
the calling module should pass values in the module block.
If you're familiar with traditional programming languages, it can be useful to compare modules to function definitions:
- Input variables are like function arguments.
- Output values are like function return values.
- Local values are like a function's temporary local variables.
For brevity, input variables are often referred to as just "variables" or "OpenTofu variables" when it is clear from context what sort of variable is being discussed. Other kinds of variables in OpenTofu include environment variables (set by the shell where OpenTofu runs) and expression variables (used to indirectly represent a value in an expression).
Declaring an Input Variable​
Each input variable accepted by a module must be declared using a variable
block:
variable "image_id" {
type = string
}
variable "availability_zone_names" {
type = list(string)
default = ["us-west-1a"]
}
variable "docker_ports" {
type = list(object({
internal = number
external = number
protocol = string
}))
default = [
{
internal = 8300
external = 8300
protocol = "tcp"
}
]
}
The label after the variable keyword is a name for the variable, which must
be unique among all variables in the same module. This name is used to
assign a value to the variable from outside and to reference the variable's
value from within the module.
The name of a variable can be any valid identifier
except the following: source, version, providers, count, for_each, lifecycle, depends_on, locals.
These names are reserved for meta-arguments in module configuration blocks, and cannot be declared as variable names.
Arguments​
OpenTofu CLI defines the following optional arguments for variable declarations:
default- A default value which then makes the variable optional.type- This argument specifies what value types are accepted for the variable.description- This specifies the input variable's documentation.validation- A block to define validation rules, usually in addition to type constraints.sensitive- Limits OpenTofu UI output when the variable is used in configuration.ephemeral- Limits the usage of the variable to ephemeral contexts.nullable- Specify if the variable can benullwithin the module.deprecated- Mark the variable as deprecated to warn callers about migration.
Default values​
The variable declaration can also include a default argument. If present,
the variable is considered to be optional and the default value will be used
if no value is set when calling the module or running OpenTofu. The default
argument requires a literal value and cannot reference other objects in the
configuration.
Type Constraints​
The type argument in a variable block allows you to restrict the
type of value that will be accepted as
the value for a variable. If no type constraint is set then a value of any type
is accepted.
While type constraints are optional, we recommend specifying them; they can serve as helpful reminders for users of the module, and they allow OpenTofu to return a helpful error message if the wrong type is used.
Type constraints are created from a mixture of type keywords and type constructors. The supported type keywords are:
stringnumberbool
The type constructors allow you to specify complex types such as collections:
list(<TYPE>)set(<TYPE>)map(<TYPE>)object({<ATTR NAME> = <TYPE>, ... })tuple([<TYPE>, ...])
The keyword any may be used to indicate that any type is acceptable. For
more information on the meaning and behavior of these different types, as well
as detailed information about automatic conversion of complex types, see
Type Constraints.
If both the type and default arguments are specified, the given default
value must be convertible to the specified type.
Input Variable Documentation​
Because the input variables of a module are part of its user interface, you can
briefly describe the purpose of each variable using the optional
description argument:
variable "image_id" {
type = string
description = "The id of the machine image (AMI) to use for the server."
}
The description should concisely explain the purpose of the variable and what kind of value is expected. This description string might be included in documentation about the module, and so it should be written from the perspective of the user of the module rather than its maintainer. For commentary for module maintainers, use comments.
Custom Validation Rules​
You can specify custom validation rules for a particular variable by adding a validation block within the corresponding variable block. The example below checks whether the AMI ID has the correct syntax.
variable "image_id" {
type = string
description = "The id of the machine image (AMI) to use for the server."
validation {
condition = length(var.image_id) > 4 && substr(var.image_id, 0, 4) == "ami-"
error_message = "The image_id value must be a valid AMI id, starting with \"ami-\"."
}
}
Refer to Custom Condition Checks for more details.
Suppressing Values in CLI Output​
Setting a variable as sensitive prevents OpenTofu from showing its value in
the plan or apply output, when you use that variable elsewhere in your
configuration.
OpenTofu will still record sensitive values in the state, and so anyone who can access the state data will have access to the sensitive values in cleartext. For more information, see Sensitive Data in State.
Declare a variable as sensitive by setting the sensitive argument to true:
variable "user_information" {
type = object({
name = string
address = string
})
sensitive = true
}
resource "some_resource" "a" {
name = var.user_information.name
address = var.user_information.address
}
Any expressions whose result depends on the sensitive variable will be treated
as sensitive themselves, and so in the above example the two arguments of
resource "some_resource" "a" will also be hidden in the plan output:
OpenTofu will perform the following actions:
# some_resource.a will be created
+ resource "some_resource" "a" {
+ name = (sensitive value)
+ address = (sensitive value)
}
Plan: 1 to add, 0 to change, 0 to destroy.
In some cases where you use a sensitive variable inside a nested block, OpenTofu may treat the entire block as redacted. This happens for resource types where all of the blocks of a particular type are required to be unique, and so disclosing the content of one block might imply the content of a sibling block.
# some_resource.a will be updated in-place
~ resource "some_resource" "a" {
~ nested_block {
# At least one attribute in this block is (or was) sensitive,
# so its contents will not be displayed.
}
}
A provider can also declare an attribute as sensitive, which will cause OpenTofu to hide it from regular output regardless of how you assign it a value. For more information, see Sensitive Resource Attributes.
If you use a sensitive value as part of an output value then OpenTofu will require you to also mark the output value itself as sensitive, to confirm that you intended to export it.
Cases where OpenTofu may disclose a sensitive variable​
A sensitive variable is a configuration-centered concept, and values are sent to providers without any obfuscation. A provider error could disclose a value if that value is included in the error message. For example, a provider might return the following error even if "foo" is a sensitive value: "Invalid value 'foo' for field"
If a resource attribute is used as, or part of, the provider-defined resource id, an apply will disclose the value. In the example below, the prefix attribute has been set to a sensitive variable, but then that value ("jae") is later disclosed as part of the resource id:
# random_pet.animal will be created
+ resource "random_pet" "animal" {
+ id = (known after apply)
+ length = 2
+ prefix = (sensitive value)
+ separator = "-"
}
Plan: 1 to add, 0 to change, 0 to destroy.
...
random_pet.animal: Creating...
random_pet.animal: Creation complete after 0s [id=jae-known-mongoose]
Ephemerality​
Setting a variable as ephemeral restricts its usage to the following ephemeral contexts:
- Ephemeral Resources
- Ephemeral Variables
- Ephemeral Outputs
- Locals
- Providers
- Provisioners
- Resource
connectionblocks - Resource
write-onlyattributes
OpenTofu will not store ephemeral variable values in the state at all. Only the variable names will be saved in the plan for further processing during apply.
Declare a variable as ephemeral by setting the ephemeral argument to true:
variable "user_password" {
type = string
ephemeral = true
}
Any expressions whose result depends on the ephemeral variable will be treated as ephemeral themselves.
locals {
sanitized = trimspace(var.user_password) # `sanitized` is an ephemeral local now
}
If you use an ephemeral value as part of an output value then OpenTofu will require you to also configure the output block as ephemeral too.
Ephemeral variables on root modules require careful handling around -var/-var-file. Please refer to tofu apply docs
Disallowing Null Input Values​
The nullable argument in a variable block controls whether the module caller
may assign the value null to the variable.
variable "example" {
type = string
nullable = false
}
The default value for nullable is true. When nullable is true, null
is a valid value for the variable, and the module configuration must always
account for the possibility of the variable value being null. Passing a
null value as a module input argument will override any default value.
Setting nullable to false ensures that the variable value will never be
null within the module. If nullable is false and the variable has a
default value, then OpenTofu uses the default when a module input argument is null.
The nullable argument only controls where the direct value of the variable may be null.
For variables of collection or structural types, such as lists or objects,
the caller may still use null in nested elements or attributes, as long as
the collection or structure itself is not null.