How to use Variables to customize Terraform configuration
Introduction Unlike variables in traditional programming languages, Terraform input variables remain constant throughout a Terraform run—whether it's during plan, apply, or destroy. Instead of changing dynamically, they let users safely tailor infrastructure by supplying different values ahead of execution, eliminating the need to manually modify configuration files. Requirements Latest Terraform installed locally An AWS Account A HCP Terraform account with HCP Terraform locally authenticated. A HCP Terraform variable set configured with your AWS credentials. VS Code. Create infrastructure Clone the Learn Terraform variables GitHub repository for this tutorial by running the following command: git clone https://github.com/hashicorp-education/learn-terraform-variables Change to the repository directory. cd learn-terraform-variables The configuration in main.tf sets up a web application by provisioning a VPC, a load balancer, and a set of EC2 instances. Open your terraform.tf file and uncomment the cloud block. Then, replace the placeholder organization name with your own HCP Terraform organization name. Run terraform init to initialize your configuration. Run terraform apply to apply the configuration. Introduce variables to customize your setup To use an input variable for an argument, start by defining the variable, then update your configuration to reference it instead of a hardcoded value. You will start using variable for your aws region by adding a block declaring a variable named aws_region to variables.tf variable "aws_region" { description = "AWS region" type = string default = "us-west-2" } NOTE: After defining your variable, you can reference it in the main configuration by using var.[variable_name] i.e. var.aws_regions for your aws region variables. Edit the provider block in main.tf to use the new aws_region variable. Add another declaration for the vpc_cidr_block variable to variables.tf. variable "vpc_cidr_block" { description = "CIDR block for VPC" type = string default = "10.0.0.0/16" } Now, replace the hard-coded value for the VPC's CIDR block with a variable in main.tf. Apply the updated configuration. Because the variable defaults match the original hardcoded values, Terraform will detect no changes and apply nothing new. Set the number of instances In addition to strings, Terraform supports several other variable types. To specify the number of instances this configuration should support, use the number type by adding the following to your variables.tf file. variable "instance_count" { description = "Number of instances to provision." type = number default = 2 } Update EC2 instances to use the instance_count variable in main.tf. Enable or disable VPN gateway support Besides strings and numbers, Terraform also supports other variable types, including bool for representing true or false values. You can use a bool variable to control whether a VPN gateway should be configured for your VPC. To do this, add the following to your variables.tf file. variable "enable_vpn_gateway" { description = "Enable a VPN gateway in your VPC." type = bool default = false } Use this new variable in your VPC configuration by editing main.tf as follows. List public and private subnets So far, the variables you've used have been single values, which Terraform refers to as simple types. In addition to these, Terraform also supports collection variable types, which can hold multiple values. There are several types of collections: List: A sequence of values, all of the same type. Map: A key-value lookup table, where both keys and values are of the same type. Set: An unordered collection of unique values, all of the same type. A common scenario for using list variables is when configuring the private_subnets and public_subnets arguments for the VPC. You can make this configuration more flexible and customizable by utilizing lists and the slice() function. variable "public_subnet_count" { description = "Number of public subnets." type = number default = 2 } variable "private_subnet_count" { description = "Number of private subnets." type = number default = 2 } variable "public_subnet_cidr_blocks" { description = "Available cidr blocks for public subnets." type = list(string) default = [ "10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24", "10.0.4.0/24", "10.0.5.0/24", "10.0.6.0/24", "10.0.7.0/24", "10.0.8.0/24", ] } variable "private_subnet_cidr_blocks" { description = "Available cidr blocks for private subnets." type = list(string) default = [ "10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24", "10.0.104.0/24", "10.0.105.0/24", "10.0.106.0/24", "10.

Introduction
Unlike variables in traditional programming languages, Terraform input variables remain constant throughout a Terraform run—whether it's during plan, apply, or destroy. Instead of changing dynamically, they let users safely tailor infrastructure by supplying different values ahead of execution, eliminating the need to manually modify configuration files.
Requirements
- Latest Terraform installed locally
- An AWS Account
- A HCP Terraform account with HCP Terraform locally authenticated.
- A HCP Terraform variable set configured with your AWS credentials.
- VS Code.
Create infrastructure
- Clone the Learn Terraform variables GitHub repository for this tutorial by running the following command:
git clone https://github.com/hashicorp-education/learn-terraform-variables
- Change to the repository directory.
cd learn-terraform-variables
The configuration in main.tf sets up a web application by provisioning a VPC, a load balancer, and a set of EC2 instances.
- Open your terraform.tf file and uncomment the cloud block. Then, replace the placeholder organization name with your own HCP Terraform organization name.
- Run
terraform init
to initialize your configuration. - Run
terraform apply
to apply the configuration.
Introduce variables to customize your setup
To use an input variable for an argument, start by defining the variable, then update your configuration to reference it instead of a hardcoded value.
- You will start using variable for your aws region by adding a block declaring a variable named aws_region to variables.tf
variable "aws_region" {
description = "AWS region"
type = string
default = "us-west-2"
}
NOTE: After defining your variable, you can reference it in the main configuration by using var.[variable_name] i.e. var.aws_regions for your aws region variables.
- Edit the provider block in main.tf to use the new aws_region variable.
- Add another declaration for the vpc_cidr_block variable to variables.tf.
variable "vpc_cidr_block" {
description = "CIDR block for VPC"
type = string
default = "10.0.0.0/16"
}
- Now, replace the hard-coded value for the VPC's CIDR block with a variable in main.tf.
- Apply the updated configuration. Because the variable defaults match the original hardcoded values, Terraform will detect no changes and apply nothing new.
Set the number of instances
In addition to strings, Terraform supports several other variable types.
To specify the number of instances this configuration should support, use the number type by adding the following to your variables.tf file.
variable "instance_count" {
description = "Number of instances to provision."
type = number
default = 2
}
- Update EC2 instances to use the instance_count variable in main.tf.
Enable or disable VPN gateway support
Besides strings and numbers, Terraform also supports other variable types, including bool for representing true or false values.
You can use a bool variable to control whether a VPN gateway should be configured for your VPC. To do this, add the following to your variables.tf file.
variable "enable_vpn_gateway" {
description = "Enable a VPN gateway in your VPC."
type = bool
default = false
}
- Use this new variable in your VPC configuration by editing main.tf as follows.
List public and private subnets
So far, the variables you've used have been single values, which Terraform refers to as simple types. In addition to these, Terraform also supports collection variable types, which can hold multiple values. There are several types of collections:
List: A sequence of values, all of the same type.
Map: A key-value lookup table, where both keys and values are of the same type.
Set: An unordered collection of unique values, all of the same type.
A common scenario for using list variables is when configuring the private_subnets and public_subnets arguments for the VPC. You can make this configuration more flexible and customizable by utilizing lists and the slice() function.
variable "public_subnet_count" {
description = "Number of public subnets."
type = number
default = 2
}
variable "private_subnet_count" {
description = "Number of private subnets."
type = number
default = 2
}
variable "public_subnet_cidr_blocks" {
description = "Available cidr blocks for public subnets."
type = list(string)
default = [
"10.0.1.0/24",
"10.0.2.0/24",
"10.0.3.0/24",
"10.0.4.0/24",
"10.0.5.0/24",
"10.0.6.0/24",
"10.0.7.0/24",
"10.0.8.0/24",
]
}
variable "private_subnet_cidr_blocks" {
description = "Available cidr blocks for private subnets."
type = list(string)
default = [
"10.0.101.0/24",
"10.0.102.0/24",
"10.0.103.0/24",
"10.0.104.0/24",
"10.0.105.0/24",
"10.0.106.0/24",
"10.0.107.0/24",
"10.0.108.0/24",
]
}
You can read more about slice() function Here
- Next, update the VPC module configuration in main.tf to use the slice() function to extract specific subsets of the CIDR block lists for your public and private subnets.
Map resource tags
Each resource and module defined in main.tf includes two tags: project_name and environment. To manage these tags efficiently, define them using a variable of type map.
- Declare a new map variable for resource tags in variables.tf.
variable "resource_tags" {
description = "Tags to set for all resources"
type = map(string)
default = {
project = "project-alpha",
environment = "dev"
}
}
By setting the type to map(string), you are telling Terraform to expect a map where all values are strings. Map keys in Terraform are always strings by default. Similar to dictionaries or maps in other programming languages, you can access a specific value by referencing its associated key.
- Now, replace the hard coded tags in main.tf with references to the new variable.
Be sure to replace all five references to these hard-coded tags in your configuration.
- Run terraform apply to apply the configuration.
Assign values to variables
Terraform requires that every variable be assigned a value. There are several ways to provide these values, including use command line flag, assign values with a file.
Use command line flag
Up to this point, all variable definitions have included default values. Now, add a new variable to variables.tf without a default value. This will require the value to be provided explicitly when running Terraform.
variable "ec2_instance_type" {
description = "AWS EC2 instance type."
type = string
}
- Replace the reference to the EC2 instance type in main.tf.
- Now apply the configuration using the -var command-line flag to provide the variable value. Since the value you're supplying matches the existing one, Terraform will detect no changes and nothing will be applied.
terraform apply -var ec2_instance_type=t2.micro
Assign values with a file
Manually entering variable values can be time-consuming and prone to errors. A better approach is to store these values in a file, allowing for easier reuse and improved consistency.
- Create a file named terraform.auto.tfvars with the following contents.
resource_tags = {
project = "project-alpha",
environment = "dev",
owner = "me@example.com"
}
ec2_instance_type = "t3.micro"
instance_count = 3
Terraform automatically loads any file in the current directory named terraform.tfvars or ending with .auto.tfvars. If your variable values are stored in a file with a different name, you can explicitly load it using the -var-file flag.
- Run terraform apply to apply the configuration.
Interpolate variables in strings
Terraform configurations support string interpolation, which lets you insert the result of expressions directly into strings. This makes it possible to dynamically build strings using variables, local values, and function outputs.
Now, update the names of the security groups to include the project and environment values from the resource_tags map variable using string interpolation.
name = "web-sg-${var.resource_tags["project"]}-${var.resource_tags["environment"]}"
name = "lb-sg-${var.resource_tags["project"]}-${var.resource_tags["environment"]}"
name = "lb-${random_string.lb_id.result}-${var.resource_tags["project"]}-${var.resource_tags["environment"]}"
- Run terraform apply
Validate variables
This configuration has a potential issue: AWS load balancers have naming restrictions. Their names must not exceed 32 characters and can only include certain characters.
To help prevent invalid tag values from causing problems, use variable validation to enforce constraints on the project and environment tags.
Replace your existing resource_tags variable in variables.tf with the following snippet. It includes validation blocks that restrict both the character set and length for the project and environment values:
variable "resource_tags" {
description = "Tags to set for all resources"
type = map(string)
default = {
project = "my-project",
environment = "dev"
}
validation {
condition = length(var.resource_tags["project"]) <= 16 && length(regexall("[^a-zA-Z0-9-]", var.resource_tags["project"])) == 0
error_message = "The project tag must be no more than 16 characters, and only contain letters, numbers, and hyphens."
}
validation {
condition = length(var.resource_tags["environment"]) <= 8 && length(regexall("[^a-zA-Z0-9-]", var.resource_tags["environment"])) == 0
error_message = "The environment tag must be no more than 8 characters, and only contain letters, numbers, and hyphens."
}
}
The regexall() function takes two arguments: a regular expression and a string to test. It returns a list of all matches found in the string. In this context, you can use a regular expression that matches any character other than a letter, number, or hyphen to detect invalid input.
- Run terraform apply to apply the configuration.
- Now test the validation rules by specifying an environment tag that is too long. Notice that the command will fail and return the error message specified in the validation block.
terraform apply -var='resource_tags={project="my-project",environment="development"}'
Thanks for staying till the end