Terraform Input Variables
Input variables make Terraform configurations flexible and reusable. Instead of hardcoding values, you declare variables for anything that changes between environments, deployments, or users — then supply the actual values separately.
Declaring Input Variables
variable "environment" { description = "Target deployment environment" type = string default = "dev"}
variable "instance_count" { description = "Number of application server instances" type = number default = 2}
variable "enable_deletion_protection" { description = "Prevent accidental database deletion" type = bool default = true}
variable "allowed_cidr_blocks" { description = "CIDR blocks allowed to reach the application load balancer" type = list(string) default = ["0.0.0.0/0"]}
variable "database_config" { description = "RDS database configuration" type = object({ engine = string engine_version = string instance_class = string allocated_storage = number }) default = { engine = "postgres" engine_version = "16.3" instance_class = "db.t3.micro" allocated_storage = 20 }}Using Variables in Configuration
Reference variables with var.<variable_name>:
resource "aws_instance" "app" { count = var.instance_count instance_type = var.environment == "production" ? "t3.large" : "t3.micro" tags = { Environment = var.environment Name = "app-${var.environment}-${count.index + 1}" }}
resource "aws_db_instance" "main" { engine = var.database_config.engine engine_version = var.database_config.engine_version instance_class = var.database_config.instance_class allocated_storage = var.database_config.allocated_storage deletion_protection = var.enable_deletion_protection}Supplying Variable Values
1. terraform.tfvars (Auto-Loaded)
environment = "staging"instance_count = 3
allowed_cidr_blocks = [ "10.0.0.0/8", "172.16.0.0/12"]
database_config = { engine = "postgres" engine_version = "16.3" instance_class = "db.t3.small" allocated_storage = 50}2. Named .tfvars Files
terraform apply -var-file="environments/production.tfvars"terraform apply -var-file="environments/staging.tfvars"3. Environment Variables
Terraform reads environment variables prefixed with TF_VAR_:
export TF_VAR_environment="production"export TF_VAR_instance_count="5"terraform apply4. Command-Line -var Flag
terraform apply -var="environment=production" -var="instance_count=5"Variable Precedence (Highest to Lowest)
-varand-var-filecommand-line flags*.auto.tfvarsand*.auto.tfvars.jsonfiles (alphabetical order)terraform.tfvars.jsonterraform.tfvars- Environment variables (
TF_VAR_*) - Default values in
variableblocks
Variables with Validation
variable "environment" { type = string default = "dev"
validation { condition = contains(["dev", "staging", "production"], var.environment) error_message = "environment must be 'dev', 'staging', or 'production'." }}
variable "instance_type" { type = string
validation { condition = can(regex("^(t3|t3a|m6i|m6a|c6i)\\.(micro|small|medium|large|xlarge|2xlarge)$", var.instance_type)) error_message = "Must be a valid EC2 instance type in the approved family." }}
variable "port" { type = number default = 8080
validation { condition = var.port >= 1024 && var.port <= 65535 error_message = "Port must be between 1024 and 65535." }}
variable "tags" { type = map(string)
validation { condition = contains(keys(var.tags), "Team") && contains(keys(var.tags), "CostCenter") error_message = "Tags map must include 'Team' and 'CostCenter' keys." }}Sensitive Variables
variable "database_password" { description = "RDS master password" type = string sensitive = true # Value hidden in plan/apply output and state}
variable "api_key" { type = string sensitive = true}When sensitive = true:
- Value is redacted in plan output:
(sensitive value) - Value is redacted in apply output
- Still stored in state (state must also be protected)
# Pass sensitive values via environment variables — never in terraform.tfvarsexport TF_VAR_database_password="$(aws secretsmanager get-secret-value \ --secret-id prod/rds/password --query SecretString --output text)"Complex Variable Types
# List of objectsvariable "users" { type = list(object({ name = string email = string role = string })) default = [ { name = "Alice", email = "alice@example.com", role = "admin" }, { name = "Bob", email = "bob@example.com", role = "reader" } ]}
resource "aws_iam_user" "team" { for_each = { for u in var.users : u.name => u } name = each.value.name tags = { Email = each.value.email Role = each.value.role }}
# Map of objectsvariable "environments" { type = map(object({ instance_type = string instance_count = number enable_ha = bool })) default = { dev = { instance_type = "t3.micro" instance_count = 1 enable_ha = false } production = { instance_type = "t3.large" instance_count = 3 enable_ha = true } }}