top of page

A Comprehensive Guide into Terraform Variables

Writer's picture: Joshua AdeyemiJoshua Adeyemi


In Terraform, variables act as placeholders for dynamic values that can change at different stages of running a configuration, much like variables in programming.


By using variables, you can customise parts of your infrastructure configuration without modifying the core logic of your Terraform modules. You can define variables directly within your Terraform configuration files or keep them in separate input files (e.g., .tfvars) to make assigning values more efficient.


This article provides a comprehensive guide to managing Terraform variables. By following these practices, you'll develop the skills to use variables effectively and create more efficient, maintainable Terraform configurations for your infrastructure projects.


Terraform variables: the building blocks of flexible infrastructure


When writing Terraform configurations, it's tempting to directly input fixed values, such as server names, as hard-coded parameters. This approach works well for managing smaller infrastructure environments, as it simplifies the workflow and boosts development efficiency.


However, using hard-coded values in several places becomes wasteful as infrastructure expands and the software gets more complicated, and more importantly is a security risk. Terraform variables become crucial at this point.


Variables enhance flexibility while maintaining clarity by allowing you to define a value once and reuse it throughout the configuration. By centralising values in one location, Terraform setups become more organised, manageable, and readable, all while improving reusability.


Difference between hardcoded values and variables


Hardcoded values in Terraform configurations are fixed inputs directly embedded into the code. While simple to implement, this method can create rigidity, making the configuration less adaptable to changes and are a security risk. 


For example, when you specify an instance type directly within a resource block, you must modify the code every time you need to change the instance type.


However, Terraform variables make updates easier by parameterising values. With these variables, you can dynamically assign values through environment variables, variable definition files, or command-line input. 


For instance, by introducing an instance_type variable, you can easily change the instance type without modifying the core setup code.

Managing Terraform input variables


Terraform modules enable users to define Infrastructure as Code (IaC) that can be reused across multiple environments and configurations due to their flexible and modular design. This reusability is primarily made possible by using input variables.


In a parent-child module relationship, the parent module is responsible for passing values to the child module through the module block. By avoiding hardcoding certain values and guaranteeing that the child module receives the right inputs and functions as intended, this method reduces mistakes.


To define an input variable within a module, you must use the variable block. This block sets up the variable and defines its properties.


Here is an example of how to define input variables within a module:


This Terraform configuration defines essential variables to streamline and optimise cloud deployments. The instance_type variable, set as a string, determines the EC2 instance type, ensuring flexibility in instance selection.


Meanwhile, the subnet_ids variable, structured as a list of strings, allows users to specify multiple subnets for launching resources, enhancing scalability and network efficiency.


Additionally, the app_config variable, defined as a list of objects, provides structured application deployment details, including name, version, and environment. This modular approach enhances powerful infrastructure flexibility, making it easier to manage and scale applications across different environments like production and staging.


For a deeper dive into Terraform's best practices and cloud automation strategies, explore Syntasso’s blog to enhance your infrastructure management skills.


What to know about output variables


In programming, output variables function like return values, enabling modules to share data with other parts of the resource configuration. These outputs enhance the usability of your infrastructure code and serve several important purposes.


Output variables are often used to pass specific resource properties from a child module to its parent module. This clean coding practice allows the parent module to access crucial data without directly referencing the internal resources of the child module.


Additionally, after running terraform apply, output variables provide valuable information in the command-line interface. This is especially useful when you need to quickly retrieve values like IP addresses, resource IDs, or URLs without digging through state files.


In systems using remote state, output variables become even more powerful. These output variables can be accessed by other Terraform configurations through the terraform_remote_state data source, simplifying data exchange between different projects or environments.

The output block is used to provide the value you wish to disclose in order to construct an output variable. Here is a simple illustration:



Beyond simply defining the value, Terraform allows you to enhance your output variables with several optional arguments that improve security and dependency management.


1. Description


The description parameter clarifies the purpose of the output variable, improving understanding for future use. Including clear explanations is a key practice for keeping the code organised. Therefore, it ensures the code remains accessible and easier to maintain over time.



2. Sensitive


The sensitive property prevents private data, like passwords or secret keys, from appearing in the CLI output during Terraform Plan or Terraform Apply. Sensitive information is kept hidden thanks to the additional security this provides.



3. Depends_on


The depends_on argument defines explicit dependencies for the output variable. This is especially important when a parent module depends on outputs from child modules that require specific resources to be created first.



Best practices for local values


Local values help eliminate repetitive expressions and streamline configuration changes. However, overusing them can lead to reduced readability, making it more challenging for future maintainers to understand the values being utilised.


A structured approach is to group related local values within a local block, ensuring the configuration remains clear and organised.


Local values are not limited to static assignments. They can dynamically reference variables, resource attributes, and other local values:



Terraform primitive data types


Primitive data types are the foundational types in Terraform, and they include:


1. String variable

In Terraform, strings are enclosed in double quotes, such as "this". For more complex strings, you can utilise the heredoc syntax for improved readability and formatting.



2. Numbers

Numbers in Terraform are expressed as digits, which can either include a decimal point or not. Examples include whole numbers like 15 or decimal numbers like 6.283185. This flexibility allows you to accurately represent both integers and floating-point values in your configurations accurately.



3. Boolean variables

Booleans in Terraform define logical values, allowing configurations to evaluate conditions as either true or false values. This makes it possible for your infrastructure code to contain conditional expressions.



Terraform complex data types


In Terraform, complex data types enhance configuration scalability by allowing the grouping of multiple values into structured collections. These complex types include:


1. Lists and Tuples


Lists and tuples are defined using square brackets, with values separated by commas, such as ["a", 15, true]. For improved readability, you can also spread them across multiple lines.

Example of a List in Terraform:



Example of a Tuple in Terraform:



2. Sets


In Terraform, sets are unordered collections, meaning you cannot access their elements by index.

To retrieve elements by position, you can convert a set to a list using the tolist function. However, since sets are unordered, the resulting list will have an undefined order that remains consistent within a particular Terraform run.



3. Maps/Object variable


Map variables (or objects) are defined using curly braces {} containing key-value pairs. This structure allows you to group related data together, enhancing the organisation and readability of your configurations. For example:



Defining default variable values


Setting default values for variables in Terraform enhances the configuration user experience. Here are the key features to consider:


  • Simplification: Assigning default values to variables streamlines configurations by predefining commonly used settings. This reduces repetitive input and minimises potential errors.

  • Implementation: Within a variable block, the default argument specifies the value to use if none is provided during execution. This ensures the configuration operates with its default settings unless overridden.

  • Mandatory inputs: If a variable lacks a default value, Terraform prompts the user to supply one during execution. This ensures all necessary information is available for the configuration parameters to function correctly.


Below is an example demonstrating how to set default values for various variables:



Defining custom validation rules


With Terraform, you can define custom validation rules for input variables to ensure they meet specific criteria before deployment. This is achieved by adding a validation block within the corresponding variable block. 

For example, to validate that an AMI ID starts with "ami-", you can implement the following:



Understanding Terraform variable precedence


Variables in Terraform may be defined from various sources. When a variable is assigned more than once, Terraform follows a specific order of precedence to determine which value to use, with later sources overriding earlier ones.

However, it is essential to note that a variable cannot be defined multiple times within the same source.


Terraform’s variable precedence order

Terraform applies precedence from the lowest to the most significant priority while evaluating and loading variables in an organised manner. The order is as follows:


  1. Environment variables: Terraform first looks for environment variables prefixed with TF_VAR_ These variables can be set outside the configuration, making them useful for automation and CI/CD pipelines.


  2. terraform.tfvars file (if present): If a terraform.tfvars file is present in the current directory, Terraform will load it next. This file enables users to define variables in a structured format within the configuration itself.


  3. terraform.tfvars.json file (if present): If a JSON-formatted version of the variable file exists (terraform.tfvars.json), it is processed after terraform.tfvars. JSON formatting is helpful for integrations with external tools that generate configuration files dynamically.


  4. Auto-loading variable files (*.auto.tfvars and *.auto.tfvars.json): Terraform automatically identifies and processes variable files with the .auto.tfvars or .auto.tfvars.json extensions. If multiple files of this kind are present, they are processed in lexical order (alphabetical sorting by filename).

     For instance:

  • 01-default.auto.tfvars

  • 02-custom.auto.tfvars

  • Command-line arguments (-var and -var-file): Any variables defined explicitly using the -var flag or -var-file flag option during execution take the highest precedence.


Using variable definitions file


Terraform's variable definition files, typically ending with .tfvars or .tfvars.json, provide a straightforward method to assign values to variables. 

These files maintain configurations by allowing you to manage multiple variables in a centralised location. This approach enhances the customisation of infrastructure deployments, as you can adjust numerous settings without altering the main configuration files.


Creating variable definitions files

A variable definition file in Terraform utilises the same straightforward syntax as standard Terraform configuration files. This consistency ensures ease of use across your configurations.


Example of a variable definition file:



When using JSON format, the file would look like this:



How to leverage environment variables in Terraform


Setting values in one place and using them throughout your setup is enabled by environment variables, which act like function parameters. They provide an abstraction layer that simplifies managing infrastructure resources in different contexts.

To define variables using environment variables, Terraform searches for those prefixed with TF_VAR_ followed by the variable’s name. This approach is quite helpful for automated tasks or situations where you need to run multiple Terraform commands in succession while utilising the same variables.

On a Unix machine, for instance, you can set the variable like this:



Terraform ensures that the environment variable name exactly matches the configuration on systems where variable names are case-sensitive. The previous example shows how this often results in a combination of uppercase and lowercase letters. 


Protecting sensitive data


To strengthen security in Terraform setups, refrain from embedding sensitive information like API keys or passwords directly in your code. Instead, use environment variables or dedicated secret management tools like HashiCorp Vault to inject credentials into your infrastructure securely. This approach minimises the risk of exposure, and ensures compliance with best practices. 


Reshaping platform engineering

Terraform is one of the pivotal technologies reshaping the landscape of platform engineering. To create a robust and adaptable Terraform configuration, you must go beyond resource allocation. 


The real power lies in creating a system that can evolve according to your infrastructure's shifting needs. Terraform variables play a key role in this process by separating configuration logic from dynamic values, ultimately optimising your deployments' advanced features.


Even with the use of variables, Terraform environments and services can become complicated for development teams.


Many platform teams want to make those environments and services available on-demand to development teams. This is where a platform engineering frameworks like Kratix come into play — by providing the right abstraction on top of existing Terraform configuration. 


With Kratix, development teams can self-serve the infrastructure resources they need, when they need them without having to understand the complexity of the Terraform serving up those resource behind the scenes.


To learn more about Kratix and Terraform, check out this article on integrating Kratix Promises with Terraform. 

bottom of page