# terraform / variables / configuration

Write Once, Deploy Everywhere: Input Variables

Input variables make your Terraform code dynamic, reusable, and configurable. Instead of hardcoding an instance type into main.tf and editing it for every environment, you declare a placeholder once and feed it different values from outside the configuration.

$ terraform apply
devt2.micro
testingt2.medium
productionm5.large
1
main.tf
3
Environments
0
Code Edits
# the problem

Without Variables, You Keep Editing Code

Say your company has three environments — Development, Testing, Production — and each needs a different EC2 instance type. Hardcode the value and main.tf has to change every single time you deploy somewhere new.

EnvironmentEC2 Instance
Developmentt2.micro
Testingt2.medium
Productionm5.large
main.tfHARDCODED — NOT RECOMMENDED
1 2 3 4 5 6 7 8
resource "aws_instance" "web" {
  ami           = "ami-0123456789abcdef"
  instance_type = "t2.micro"
}

// Testing: change to "t2.medium"
// Production: change to "m5.large"
// You keep editing this file every time.
# the fix

The Three-File Model

Instead of changing main.tf, keep it the same and only change the values. A typical project splits into three files, each with exactly one job.

declares

variables.tf

Tells Terraform "my project needs these values." It's an empty placeholder — no value lives here, just a name and a type. Someone will provide the value later.

provides

terraform.tfvars

Supplies the actual value for each declared variable. This is the file that changes between Development, Testing, and Production.

uses

main.tf

References the variable with var.instance_type instead of a literal string. This file never has to change again.

Reading Order

variables.tf → declares instance_type
terraform.tfvars → instance_type = "t2.medium"
main.tf → instance_type = var.instance_type
↓ Terraform substitutes the value
instance_type = "t2.medium"
variables.tfDECLARATION
1 2 3
variable "instance_type" {
  type = string
}
terraform.tfvarsVALUE
1
instance_type = "t2.medium"
main.tfUSAGE
1 2 3 4
resource "aws_instance" "web" {
  ami           = "ami-0123456789abcdef"
  instance_type = var.instance_type
}
terminal$ terraform apply
Terraform will perform the following actions:
+ aws_instance.web
instance_type = "t2.medium"
Plan: 1 to add.
Apply complete!
# six kinds

Variable Types

1

String — instance_type

Stores text. The most common variable type — instance types, regions, key pairs, AMI IDs are all strings.

variables.tf
variable "instance_type" {
  type = string
}
terraform.tfvars
instance_type = "t2.micro"
main.tf
instance_type = var.instance_type
2

Number — disk_size

Stores numeric values — EBS volume sizes, auto-scaling desired capacity, port numbers.

variables.tf
variable "disk_size" {
  type = number
}
terraform.tfvars
disk_size = 100
main.tf
size = var.disk_size
// → 100 GB EBS volume
3

Bool — monitoring

Stores true or false — feature toggles like detailed monitoring, encryption, or public access.

variables.tf
variable "monitoring" {
  type = bool
}
terraform.tfvars
monitoring = true
main.tf
monitoring = var.monitoring
// → Detailed Monitoring: Enabled
4

List — subnets

Stores an ordered collection of values of the same type, accessed by index.

variables.tf
variable "subnets" {
  type = list(string)
}
terraform.tfvars
subnets = [
  "subnet-111",
  "subnet-222",
  "subnet-333"
]
main.tf
subnet_id = var.subnets[0]
// → launched in subnet-111
5

Map — tags

Stores key-value pairs, all values sharing the same type — the classic shape for resource tags.

variables.tf
variable "tags" {
  type = map(string)
}
terraform.tfvars
tags = {
  Name = "WebServer"
  Environment = "Development"
  Owner = "DevOps"
}
main.tf
tags = var.tags
6

Object — server

Bundles several related values of different types into a single structured variable.

variables.tf
variable "server" {
  type = object({
    instance_type = string
    disk = number
    monitoring = bool
  })
}
terraform.tfvars
server = {
  instance_type = "t3.large"
  disk = 200
  monitoring = true
}
main.tf
instance_type = var.server.instance_type
monitoring = var.server.monitoring
# convenience & safety

Default Values & Validation

defaults

Skip terraform.tfvars Entirely

When almost every server uses the same region, give the variable a default right in variables.tf. There's no need to repeat it in terraform.tfvars — Terraform falls back to the default automatically.

variables.tfDEFAULT VALUE
1 2 3
variable "region" {
  default = "ap-south-1"
}
validation

Enforcing Company Policy

Say policy only allows t2.micro or t2.medium. A validation block rejects anything else with a clear error message before Terraform ever calls the provider.

variables.tfVALIDATION BLOCK
1 2 3 4 5 6 7 8
variable "instance_type" {
  validation {
    condition = contains(
      ["t2.micro","t2.medium"],
      var.instance_type
    )
    error_message = "Only t2.micro or t2.medium allowed."
  }
}
CORRECT

instance_type = "t2.micro" → Terraform Apply Successful.

WRONG

instance_type = "m5.large" → Error: Only t2.micro or t2.medium allowed.

# where values come from

Loading Values

terraform.tfvars

Terraform loads this file automatically on every apply — no flag needed.

1 2 3
region = "ap-south-1"
instance_type = "t2.micro"
disk_size = 100
*.auto.tfvars

Any file ending in .auto.tfvars — like dev.auto.tfvars, qa.auto.tfvars, prod.auto.tfvars — loads automatically too, no -var-file flag required.

dev.auto.tfvars
1
instance_type = "t2.micro"
TF_VAR_*

CI/CD pipelines (Jenkins, GitHub Actions, GitLab, Azure DevOps) inject values as environment variables instead of files.

$ export TF_VAR_instance_type="t3.large"
$ terraform apply
# putting it together

Complete Flow

variables.tf → declares instance_type
terraform.tfvars → instance_type = "t2.medium"
main.tf → instance_type = var.instance_type
↓ Terraform replaces
instance_type = "t2.medium"
AWS API
Creates EC2 · Instance Type = t2.medium

Easy Way to Remember

FileWhyExample
variables.tfDeclares what the project needsinstance_type, region
terraform.tfvarsProvides the actual valuesinstance_type = "t2.medium"
main.tfUses values to create infrastructureinstance_type = var.instance_type
TF_VAR_*Passes values from CI/CD or terminalexport TF_VAR_instance_type="m5.large"

The code in main.tf is written once. Dev, QA, and Production all run the same code — only the input values change, through terraform.tfvars, .auto.tfvars, or TF_VAR_ environment variables.