How to use Variables to customize Terraform configuration

Table of contents
- Introduction
- Requirements
- Create infrastructure
- Introduce variables to customize your setup
- Set the number of instances
- Enable or disable VPN gateway support
- List public and private subnets
- Map resource tags
- Assign values to variables
- Assign values with a file
- Interpolate variables in strings
- Validate variables

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 a variable for your AWS region by adding a block declaring a variable named aws_region to the 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 the 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",
]
}
Paste the Above in the v.tf 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 is defined in the 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 using command line flag, assigning values from a file.
Use the command line flag
Up to this point, all variable definitions have included default values. Now, add a new variable to the 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
Subscribe to my newsletter
Read articles from Chigozie Ozoemena directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Chigozie Ozoemena
Chigozie Ozoemena
Hi there! 👋 I'm Daniel Ozoemena, a passionate Cloud Solution Architect and DevOps Engineer dedicated to building scalable, secure, and innovative cloud solutions. With hands-on experience in Azure, AWS, and Google Cloud Platform, I specialize in deploying infrastructure as code, automating workflows, and optimizing system reliability. Driven by a love for problem-solving, I constantly explore new technologies and best practices to deliver impactful results. Beyond the cloud, I enjoy mentoring, blogging about tech insights, and contributing to open-source projects. When I'm not automating deployments or creating secure virtual networks, you can find me playing chess, learning about AI, or brainstorming solutions to real-world challenges. Let’s connect and grow together on this tech journey! 🚀