--- description: >- Input variables allow you to customize modules without altering their source code. Learn how to declare, define, and reference variables in configurations. --- # 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](../../language/modules/index.mdx), 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](../../language/values/outputs.mdx) are like function return values. * [Local values](../../language/values/locals.mdx) are like a function's temporary local variables. :::note 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](../../language/expressions/index.mdx)). ::: ## Declaring an Input Variable Each input variable accepted by a module must be declared using a `variable` block: ```hcl 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](../../language/syntax/configuration.mdx#identifiers) _except_ the following: `source`, `version`, `providers`, `count`, `for_each`, `lifecycle`, `depends_on`, `locals`. These names are reserved for meta-arguments in [module configuration blocks](../../language/modules/syntax.mdx), and cannot be declared as variable names. ## Arguments OpenTofu CLI defines the following optional arguments for variable declarations: * [`default`][inpage-default] - A default value which then makes the variable optional. * [`type`][inpage-type] - This argument specifies what value types are accepted for the variable. * [`description`][inpage-description] - This specifies the input variable's documentation. * [`validation`][inpage-validation] - A block to define validation rules, usually in addition to type constraints. * [`sensitive`][inpage-sensitive] - Limits OpenTofu UI output when the variable is used in configuration. * [`ephemeral`][inpage-ephemeral] - Limits the usage of the variable to ephemeral contexts. * [`nullable`][inpage-nullable] - Specify if the variable can be `null` within the module. * [`deprecated`][inpage-deprecated] - Mark the variable as deprecated to warn callers about migration. ### Default values [inpage-default]: #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 [inpage-type]: #type-constraints The `type` argument in a `variable` block allows you to restrict the [type of value](../../language/expressions/types.mdx) 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: * `string` * `number` * `bool` The type constructors allow you to specify complex types such as collections: * `list()` * `set()` * `map()` * `object({ = , ... })` * `tuple([, ...])` 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](../../language/expressions/types.mdx). If both the `type` and `default` arguments are specified, the given default value must be convertible to the specified type. ### Input Variable Documentation [inpage-description]: #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: ```hcl 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 [inpage-validation]: #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. ```hcl 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](../../language/expressions/custom-conditions.mdx#input-variable-validation) for more details. ### Suppressing Values in CLI Output [inpage-sensitive]: #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](../../language/state/index.mdx), 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_](../../language/state/sensitive-data.mdx). Declare a variable as sensitive by setting the `sensitive` argument to `true`: ```hcl 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](https://developer.hashicorp.com/terraform/plugin/best-practices/sensitive-state#using-sensitive-flag-functionality), 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](../../language/expressions/references.mdx#sensitive-resource-attributes). If you use a sensitive value as part of an [output value](../../language/values/outputs.mdx) 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 [inpage-ephemeral]: #ephemeral-variables If a variable is set to `ephemeral`, the module author will limit its usage only to the allowed ephemeral contexts: * [Ephemeral Resources](../ephemerality/ephemeral-resources.mdx) * [Ephemeral Variables](../values/variables.mdx#ephemerality) * [Ephemeral Outputs](../values/outputs.mdx#ephemerality) * [Locals](../values/locals.mdx#ephemerality) * [Providers](../providers/configuration.mdx) * [Provisioners](../resources/provisioners/syntax.mdx#suppressing-provisioner-logs-in-cli-output) * [Resource `connection` blocks](../resources/provisioners/connection.mdx#ephemeral-usage) * [Resource `write-only` attributes](../ephemerality/write-only-attributes.mdx) OpenTofu will not store this type of variables in the [state](../../language/state/index.mdx) at all. These will be saved in the plan only by their name for further processing during apply. Declare a variable as ephemeral by setting the `ephemeral` argument to `true`: ```hcl variable "user_password" { type = string ephemeral = true } ``` Any expressions whose result depends on the ephemeral variable will be treated as ephemeral themselves. ```hcl locals { sanitized = trimspace(var.user_password) # `sanitized` is an ephemeral local now } ``` If you use an ephemeral value as part of an [output value](../../language/values/outputs.mdx) then OpenTofu will require you to also configure the output block as ephemeral too. :::note Ephemeral variables on root modules require careful handling around `-var`/`-var-file`. Please refer to [`tofu apply` docs](../../cli/commands/apply.mdx#ephemeral-variables) ::: ### Disallowing Null Input Values [inpage-nullable]: #disallowing-null-input-values The `nullable` argument in a variable block controls whether the module caller may assign the value `null` to the variable. ```hcl 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. ### Marking variable as deprecated [inpage-deprecated]: #marking-variable-as-deprecated The `deprecated` argument in a variable block indicates its deprecation and potential removal in the future. This attribute should contain non-empty string and should provide instructions on how to migrate away from usage of this variable. Here is an example of the configuration: ```hcl variable "example" { type = string deprecated = "'examle' variable must no longer be used due to a typo, use 'example' instead" } ``` The caller of the module will receive a warning if the deprecated variable is used in their configuration: ``` │ Warning: Variable marked as deprecated by the module author │ │ on main.tf line 3, in module "mod": │ 3: examle = "a" │ │ Variable "examle" is marked as deprecated with the following message: │ 'examle' variable must no longer be used due to a typo, use 'example' instead ``` Deprecation warnings can be filtered or disabled by using the `-deprecation` CLI argument. By default, deprecated module variables will be consolidated by using their variable name and the deprecation message. If two different modules are using a submodule with a deprecated variable, they will be shown together. In order to see them individually, `-consolidation-warnings=false` can be used. For more details, check its description in the command options for [plan](../../cli/commands/plan.mdx#other-options) and [apply](../../cli/commands/apply.mdx#apply-options). ## Using Input Variable Values Within the module that declared a variable, its value can be accessed from within [expressions](../../language/expressions/index.mdx) as `var.`, where `` matches the label given in the declaration block: :::note Input variables are _created_ by a `variable` block, but you _reference_ them as attributes on an object named `var`. ::: ```hcl resource "aws_instance" "example" { instance_type = "t2.micro" ami = var.image_id } ``` The value assigned to a variable can only be accessed in expressions within the module where it was declared. ## Assigning Values to Root Module Variables When variables are declared in the root module of your configuration, they can be set in a number of ways: * Individually, with the `-var` command line option. * In variable definitions (`.tfvars`) files, either specified on the command line or automatically loaded. * As environment variables. The following sections describe these options in more detail. This section does not apply to _child_ modules, where values for input variables are instead assigned in the configuration of their parent module, as described in [_Modules_](../../language/modules/index.mdx). ### Variables on the Command Line To specify individual variables on the command line, use the `-var` option when running the `tofu plan` and `tofu apply` commands: ``` tofu apply -var="image_id=ami-abc123" tofu apply -var='image_id_list=["ami-abc123","ami-def456"]' -var="instance_type=t2.micro" tofu apply -var='image_id_map={"us-east-1":"ami-abc123","us-east-2":"ami-def456"}' ``` The above examples show appropriate syntax for Unix-style shells, such as on Linux or macOS. For more information on shell quoting, including additional examples for Windows Command Prompt, see [Input Variables on the Command Line](../../cli/commands/plan.mdx#input-variables-on-the-command-line). You can use the `-var` option multiple times in a single command to set several different variables. ### Variable Definitions (`.tfvars`) Files To set lots of variables, it is more convenient to specify their values in a _variable definitions file_ (with a filename ending in either `.tfvars` or `.tfvars.json`) and then specify that file on the command line with `-var-file`: ``` tofu apply -var-file="testing.tfvars" ``` A variable definitions file uses the same basic syntax as OpenTofu language files, but consists only of variable name assignments: ```hcl image_id = "ami-abc123" availability_zone_names = [ "us-east-1a", "us-west-1c", ] ``` OpenTofu also automatically loads a number of variable definitions files if they are present: * Files named exactly `terraform.tfvars` or `terraform.tfvars.json`. * Any files with names ending in `.auto.tfvars` or `.auto.tfvars.json`. Files whose names end with `.json` are parsed instead as JSON objects, with the root object properties corresponding to variable names: ```json { "image_id": "ami-abc123", "availability_zone_names": ["us-west-1a", "us-west-1c"] } ``` ### Environment Variables As a fallback for the other ways of defining variables, OpenTofu searches the environment of its own process for environment variables named `TF_VAR_` followed by the name of a declared variable. This can be useful when running OpenTofu in automation, or when running a sequence of OpenTofu commands in succession with the same variables. For example, at a `bash` prompt on a Unix system: ``` $ export TF_VAR_image_id=ami-abc123 $ tofu plan ... ``` On operating systems where environment variable names are case-sensitive, OpenTofu matches the variable name exactly as given in configuration, and so the required environment variable name will usually have a mix of upper and lower case letters as in the above example. ### Complex-typed Values When variable values are provided in a variable definitions file, you can use OpenTofu's usual syntax for [literal expressions](../../language/expressions/types.mdx#literal-expressions) to assign complex-typed values, like lists and maps. Some special rules apply to the `-var` command line option and to environment variables. For convenience, OpenTofu defaults to interpreting `-var` and environment variable values as literal strings, which need only shell quoting, and no special quoting for OpenTofu. For example, in a Unix-style shell: ``` $ export TF_VAR_image_id='ami-abc123' ``` However, if a root module variable uses a [type constraint](#type-constraints) to require a complex value (list, set, map, object, or tuple), OpenTofu will instead attempt to parse its value using the same syntax used within variable definitions files, which requires careful attention to the string escaping rules in your shell: ``` $ export TF_VAR_availability_zone_names='["us-west-1b","us-west-1d"]' ``` For readability, and to avoid the need to worry about shell escaping, we recommend always setting complex variable values via variable definitions files. For more information on quoting and escaping for `-var` arguments, see [Input Variables on the Command Line](../../cli/commands/plan.mdx#input-variables-on-the-command-line). ### Values for Undeclared Variables If you have defined a variable value, but not its corresponding `variable {}` definition, you may get an error or warning depending on how you have provided that value. If you provide values for undeclared variables defined as [environment variables](#environment-variables) you will not get an error or warning. This is because environment variables may be declared but not used in all configurations that might be run. If you provide values for undeclared variables defined [in a file](#variable-definitions-tfvars-files) you will get a warning. This is to help in cases where you have provided a variable value _meant_ for a variable declaration, but perhaps there is a mistake in the value definition. For example, the following configuration: ```hcl variable "moose" { type = string } ``` And the following `.tfvars` file: ```hcl mosse = "Moose" ``` Will cause OpenTofu to warn you that there is no variable declared `"mosse"`, which can help you spot this mistake. If you use `.tfvars` files across multiple configurations and expect to continue to see this warning, you can use the [`-compact-warnings`](../../cli/commands/plan.mdx#compact-warnings) option to simplify your output. If you provide values for undeclared variables on the [command line](#variables-on-the-command-line), OpenTofu will return an error. To avoid this error, either declare a variable block for the value, or remove the variable value from your OpenTofu call. ### Variable Definition Precedence The above mechanisms for setting variables can be used together in any combination. If the same variable is assigned multiple values, OpenTofu uses the _last_ value it finds, overriding any previous values. Note that the same variable cannot be assigned multiple values within a single source. OpenTofu loads variables in the following order, with later sources taking precedence over earlier ones: * Environment variables * The `terraform.tfvars` file, if present. * The `terraform.tfvars.json` file, if present. * Any `*.auto.tfvars` or `*.auto.tfvars.json` files, processed in lexical order of their filenames. * Any `-var` and `-var-file` options on the command line, in the order they are provided. :::warning Important Variables with map and object values behave the same way as other variables: the last value found overrides the previous values. This is a change from previous versions of OpenTofu, which would _merge_ map values instead of overriding them. :::