instruction: How do you manage multiple environments with Terraform?
output: Input Variables - Configuration Language | Terraform | HashiCorp Developer HashiConf The full conference agenda&#x27;s now LIVE. Buy your pass and plan your schedule. Register Dismiss alert HashiCorp Cloud Platform Get started in minutes with our cloud products All HCP Products Infrastructure Lifecycle Management Terraform Manage infrastructure as code Packer Build machine images Nomad Orchestrate workloads Waypoint Standardize application patterns Vagrant Build developer environments Security Lifecycle Management Vault Centrally manage secrets Boundary Secure remote access HCP Vault Radar Scan for embedded secrets Consul Secure network services Learn Certifications Get HashiCorp certified Tutorials Learn HashiCorp products Validated Patterns Field-tested patterns for using HashiCorp products Well-Architected Framework Adopt HashiCorp best practices Terraform Install Tutorials Documentation Documentation Intro to Terraform Configuration Language Terraform CLI HCP Terraform Terraform Enterprise Terraform Migrate CDK for Terraform Provider Use Plugin Development Registry Publishing Integration Program Registry (opens in new tab) Try Cloud (opens in new tab) Search Command or control key K key Sign in Sign up Theme Terraform Home Configuration Language Configuration Language Style Guide Stacks BETA BETA Files and Directories Syntax Resources Data Sources Ephemeral block Providers Variables and Outputs Overview Input Variables Output Values Local Values Modules Moved block Terraform block Backend block Checks Import Expressions Functions State Tests Upgrading to Terraform v1.12 v1.x Compatibility Promises Terraform Internals Resources Tutorial Library Certifications Community Forum (opens in new tab) Support (opens in new tab) GitHub (opens in new tab) Terraform Registry (opens in new tab) Developer Terraform Configuration Language Variables and Outputs Input Variables v1.12.x (latest) Terraform v1.13.x (rc) v1.11.x v1.10.x v1.9.x v1.8.x v1.7.x v1.6.x v1.5.x v1.4.x v1.3.x v1.2.x v1.1.x Input Variables Hands-on: Try the Customize Terraform Configuration with Variables tutorial. Input variables let you customize aspects of Terraform modules without altering the module&#x27;s own source code. This functionality allows you to share modules across different Terraform 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&#x27;re familiar with traditional programming languages, it can be useful to compare Terraform modules to function definitions: Input variables are like function arguments. Output values are like function return values. Local values are like a function&#x27;s temporary local variables. Note: For brevity, input variables are often referred to as just &quot;variables&quot; or &quot;Terraform variables&quot; when it is clear from context what sort of variable is being discussed. Other kinds of variables in Terraform include environment variables (set by the shell where Terraform 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 &quot;image_id&quot; { type = string } variable &quot;availability_zone_names&quot; { type = list ( string ) default = [ &quot;us-west-1a&quot; ] } variable &quot;docker_ports&quot; { type = list ( object ({ internal = number external = number protocol = string })) default = [ { internal = 8300 external = 8300 protocol = &quot;tcp&quot; } ] } 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&#x27;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 Terraform 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&#x27;s documentation. validation - A block to define validation rules, usually in addition to type constraints. ephemeral - This variable is available during runtime, but not written to state or plan files. sensitive - Limits Terraform UI output when the variable is used in configuration. nullable - Specify if the variable can be null within the module. 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 Terraform. 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 Terraform 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(&lt;TYPE&gt;) set(&lt;TYPE&gt;) map(&lt;TYPE&gt;) object({&lt;ATTR NAME&gt; = &lt;TYPE&gt;, ... }) tuple([&lt;TYPE&gt;, ...]) 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 &quot;image_id&quot; { type = string description = &quot;The id of the machine image (AMI) to use for the server.&quot; } 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 This feature was introduced in Terraform CLI v0.13.0. 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 &quot;image_id&quot; { type = string description = &quot;The id of the machine image (AMI) to use for the server.&quot; validation { condition = length(var . image_id) &gt; 4 &amp;&amp; substr(var . image_id , 0 , 4 ) == &quot;ami-&quot; error_message = &quot;The image_id value must be a valid AMI id, starting with \&quot;ami-\&quot;.&quot; } } Refer to Custom Condition Checks for more details. Exclude values from state Note : Ephemeral variables are available in Terraform v1.10 and later. Setting a variable as ephemeral makes it available during runtime, but Terraform omits ephemeral values from state and plan files. Marking an input variable as ephemeral is useful for data that only needs to exist temporarily, such as a short-lived token or session identifier. Mark an input variable as ephemeral by setting the ephemeral argument to true : variable &quot;session_token&quot; { type = string ephemeral = true } Ephemeral variables are available during the current Terraform operation, and Terraform does not store them in state or plan files. So, unlike sensitive inputs, Terraform ensures ephemeral values are not available beyond the lifetime of the current Terraform run. You can only reference ephemeral variables in specific contexts or Terraform throws an error. The following are valid contexts for referencing ephemeral variables: In a write-only argument Another ephemeral variable In local values In ephemeral resources In ephemeral outputs Configuring providers in the provider block In provisioner and connection blocks If another expression references an ephemeral variable, that expression implicitly becomes ephemeral. variable &quot;password&quot; { type = string ephemeral = true } locals { # local.database_password is implicitly ephemeral because # var.password is ephemeral. database_password = var.password } The local.database_password value is implicitly ephemeral because it depends on var.password . Suppressing Values in CLI Output Hands-on: Try the Protect Sensitive Input Variables tutorial. Setting a variable as sensitive prevents Terraform from showing its value in the plan or apply output, when you use that variable elsewhere in your configuration. Terraform 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. If you want to omit a value from state, mark that value as ephemeral . For more information, refer to Sensitive Data in State . Declare a variable as sensitive by setting the sensitive argument to true : variable &quot;user_information&quot; { type = object ({ name = string address = string }) sensitive = true } resource &quot;some_resource&quot; &quot;a&quot; { 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 &quot;some_resource&quot; &quot;a&quot; will also be hidden in the plan output: Terraform will perform the following actions: &nbsp; # some_resource.a will be created + resource "some_resource" "a" { + name = (sensitive value) + address = (sensitive value) } &nbsp; Plan: 1 to add, 0 to change, 0 to destroy. In some cases where you use a sensitive variable inside a nested block, Terraform 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 Terraform 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 Terraform will require you to also mark the output value itself as sensitive, to confirm that you intended to export it. Cases where Terraform 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 &quot;foo&quot; is a sensitive value: &quot;Invalid value &#x27;foo&#x27; for field&quot; 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 (&quot;jae&quot;) 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 = "-" } &nbsp; Plan: 1 to add, 0 to change, 0 to destroy. &nbsp; ... &nbsp; random_pet.animal: Creating... random_pet.animal: Creation complete after 0s [id=jae-known-mongoose] Disallowing Null Input Values This feature is available in Terraform v1.1.0 and later. The nullable argument in a variable block controls whether the module caller may assign the value null to the variable. variable &quot;example&quot; { 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 Terraform 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. Using Input Variable Values Within the module that declared a variable, its value can be accessed from within expressions as var.&lt;NAME&gt; , where &lt;NAME&gt; 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 . resource &quot;aws_instance&quot; &quot;example&quot; { instance_type = &quot;t2.micro&quot; 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: In an HCP Terraform workspace . 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 . Variables on the Command Line To specify individual variables on the command line, use the -var option when running the terraform plan and terraform apply commands: terraform apply -var="image_id=ami-abc123" terraform apply -var='image_id_list=["ami-abc123","ami-def456"]' -var="instance_type=t2.micro" terraform 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 . 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 : Linux, Mac OS, and UNIX: terraform apply -var-file=&quot;testing.tfvars&quot; PowerShell: terraform apply -var-file=&#x27;testing.tfvars&#x27; Windows cmd.exe : terraform apply -var-file=&quot;testing.tfvars&quot; Note: This is how HCP Terraform passes workspace variables to Terraform. A variable definitions file uses the same basic syntax as Terraform language files, but consists only of variable name assignments: image_id = &quot;ami-abc123&quot; availability_zone_names = [ &quot;us-east-1a&quot; , &quot;us-west-1c&quot; , ] Terraform 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: { &quot;image_id&quot; : &quot;ami-abc123&quot; , &quot;availability_zone_names&quot; : [ &quot;us-west-1a&quot; , &quot;us-west-1c&quot; ] } Environment Variables As a fallback for the other ways of defining variables, Terraform 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 Terraform in automation, or when running a sequence of Terraform commands in succession with the same variables. For example, at a bash prompt on a Unix system: $ export TF_VAR_image_id=ami-abc123 $ terraform plan ... On operating systems where environment variable names are case-sensitive, Terraform 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 Terraform&#x27;s usual syntax for 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, Terraform defaults to interpreting -var and environment variable values as literal strings, which need only shell quoting, and no special quoting for Terraform. For example, in a Unix-style shell: $ export TF_VAR_image_id='ami-abc123' However, if a root module variable uses a type constraint to require a complex value (list, set, map, object, or tuple), Terraform 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 . 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 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 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: variable &quot;moose&quot; { type = string } And the following .tfvars file: mosse = &quot;Moose&quot; Will cause Terraform to warn you that there is no variable declared &quot;mosse&quot; , 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 option to simplify your output. If you provide values for undeclared variables on the command line , Terraform will return an error. To avoid this error, either declare a variable block for the value, or remove the variable value from your Terraform 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, Terraform uses the last value it finds, overriding any previous values. Note that the same variable cannot be assigned multiple values within a single source. Terraform 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. (This includes variables set by an HCP Terraform workspace.) Important: In Terraform 0.12 and later, 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 Terraform, which would merge map values instead of overriding them. Variable precedence within Terraform tests Within Terraform test files, you can specify variable values within variables blocks, either nested within run blocks or defined directly within the file. Variables defined in this way take precedence over all other mechanisms during test execution, with variables defined within run blocks taking precedence over those defined within the file. Edit this page on GitHub On this page: Input Variables Declaring an Input Variable Arguments Using Input Variable Values Assigning Values to Root Module Variables Theme Certifications System Status Cookie Manager Terms of Use Security Privacy Trademark Policy Trade Controls Accessibility Give Feedback (opens in new tab)