Whitepaper: Increasing Developer Velocity in the Cloud Operating Model
This whitepaper discusses how HashiCorp tools and the GitHub platform work together to enable organizations to adopt a strong CI/CD workflow and increase developer velocity.
There is no denying that Terraform is one of the leading players in the Infrastructure as Code space, but the learning curve is quite steep. One of the things that can confuse newcomers to the language is the fact that there is two forms of variable files, the variable.tf and the variable.tfvars file. In fact there are actually three distinct methods of declaring variables. Let’s remove any confusion around these three methods and see what the is difference between variable.tf and variable.tfvars in Terraform?
How simple Terraform plans make hybrid and multi-cloud a reality: an introduction
Deploying a LAMP Stack with Terraform – AMIs, network & security
Deploying a LAMP Stack with Terraform – Databases & Webservers
How to create resilient Terraform code
Deploying and configuring HashiCorp Vault to service Terraform
Deploying a LAMP Stack with Terraform – Modules
Now, back to variables. The options are:
- variables files, variable.tf and variable.tfvars
- Environment variables on the host you are deploying your code from; these use the prefix TF_VAR eg TF_VAR_myvar=football
- Flags passed to the terraform command for example terraform apply -var ‘myvar=football’
What do we use a variable for?
What exactly is a variable? They are input values used by your code as configuration items. They are explicitly declared via one of the methods mentioned above and provide the hydration for dry code, allowing it to do purposeful work when run.
How do we use a variable?
Now a little bit on environment and command line declared variables. Each method has a distinct purpose. For example environment variables change default behavior in unusual situation, for example increasing logging of stderr with export TF_LOG=TRACE or a set TF_LOG=TRACE. For a for a fuller explanation read this document.
As stated you can also pass variables via the command line; you would do this to make sure that a particular variable or set of variables are overwritten from any previously by a variable.tf, variable.tfvars or any json files. A very good way to make sure that a particular set of inputs are set.
For example “terraform apply -var=”image_id=ami-xyz987654321” to pass a list or a map you would use -var=’image_id_list=[“ami-xyz987654321”,” ami-mno987654321”,” ami-abc987654321”] or –var’image_id_map={“your_string_here“,”your_string_here”,”your_string_here”}’.
All this is understandable behavior. However what often confuses newcomers to Terraform is the fact that there are two what at first look appears to be exactly the same functions.
What are the differences between variable files
The variables.tfvars file is used to define variables and the *.tf file declare that the variable exists. It is a fine distinction but important. Let me clarify.
Declaring a variable in programming means that you are declaring your intention to create the thing, or declaring that it has been created in another file. It does not hold a value yet, but it does exist.
Variable “myvar { Type = string Description = “a variable to create a string to configure some stuff” }
Here we have told terraform to expect a variable of type string to appear somewhere in our code.
Defining a variable in means that you are giving a variable a value.
myvar = “this is a string to configure some stuff”
To complicate matters you can declare and define at the same time by giving your declaration a default value.
Variable “my_var { Type = string Description = “a variable to create a string to configure some stuff” Default = “this is a string to configure some stuff” }
If you want to override a default definition, you just redefine your variable
myvar = “this is a new string that overrides my default string to configure some stuff differently”
To delete a variable, you just define it with a null value
my_var = null
Now we have some understanding of what variables are and what the difference between declaration and definition is. What is the actual difference between variable.tf and variable.tfvars in Terraform?
variable.tfvar vs. variable.tf
So, what is the difference between variable.tf and variable.tfvars in Terraform?
The tfvars file extension is in the root folder of an environment to define values to variables, and the .tf uses modules to declare them, however what complicates matters is that people have used tfvars files in modules and tf files in the root module.
So we use a *.tfvar file to load in defaults as they are automatically loaded without any additional command line option.
As these are automatically loaded, you can have your orchestration Automator dynamically create a tfvars file to define defaults such as Region, environment (dev, test, stage or prod) cidr_blocks, subnet ranges, etc.
Child modules and hierarchy of processing
However the difference really starts be become apparent when you are dealing with child modules in your code as a *.tfvar file ONLY applies to root module variables; however, any defaults set in a variable will also apply to child modules.
Consider this example…
Sport ├── Football │ ├── America │ │ └── terraform.tfvars │ └── terraform.tfvars
If we have the variable myvar = “football” defined in sport/football/terraform.tfvars and myvar = “soccer” defined in sport/football/America/terraform.tfvars, normally you would expect that the value of the myvar variable to set to “soccer”. But this is not the case it is set to “football”, which incidentally is correct (both for the sport and for the variable), as child module .tfvar files are treated as optional and root tfvars required and authoritative. If you need to change the variable from “football” to “soccer” the you would add that variable to a .tf file in the folder that the module runs.
According to the terraform documentation on input variables, Terraform loads variables in the following order, with later sources taking precedence over earlier ones:
- Environment variables
- The tfvarsfile, if present.
- The tfvars.jsonfile, 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 order they are provided. (This includes variables set by a Terraform Cloud workspace.)
Wait a minute there is no mention of .tf file declaration in there, this is because variables declared in .tf files are concatenated into a single entity consisting of your variables.tf your main.tf and your output.tf files before being processed by terraform. Hence this declaration have highest precedence in order of application.
Summary
To sum up the difference between variable.tf and variable.tfvars in Terraform, the variables.tf just defines valid variables for your templates. The tfvars file declares them thus giving those variables values. Any overriding of the defaults that are set in your *.tfvar file, should be in a variables.tf file in the relevant directory of the module requiring the new variable, One thing to note though is that unless you use a separate directory structure and separate state files to handle each environment, you will overwrite any existing environment.