Skip to content

Terraform_variables

This chapter covers input variables, output values, and local values in Terraform.

Input variables let you parameterize your Terraform configurations, making them flexible and reusable.

┌─────────────────────────────────────────────────────────────────────────────┐
│ Input Variables Overview │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Variable Declaration │ │
│ │ │ │
│ │ variable "name" { │ │
│ │ type = string # or number, bool, list, map │ │
│ │ description = "Explanation" │ │
│ │ default = "value" # Optional │ │
│ │ validation = { ... } # Optional │ │
│ │ sensitive = false # Optional │ │
│ │ nullable = true # Optional │ │
│ │ } │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │
│ Variable Types: │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ string │ │ number │ │ bool │ │ list │ │ map │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
# String variable
variable "environment" {
description = "Environment name"
type = string
default = "dev"
}
# Number variable
variable "instance_count" {
description = "Number of instances to create"
type = number
default = 3
}
# Boolean variable
variable "enable_monitoring" {
description = "Enable CloudWatch monitoring"
type = bool
default = true
}
# List (array) variable
variable "availability_zones" {
description = "AZs for subnets"
type = list(string)
default = ["us-east-1a", "us-east-1b", "us-east-1c"]
}
# Map variable
variable "instance_tags" {
description = "Tags for instances"
type = map(string)
default = {
Environment = "Production"
Team = "Platform"
Project = "WebApp"
}
}
# Set variable
variable "allowed_cidrs" {
description = "Allowed CIDR blocks"
type = set(string)
default = ["10.0.0.0/16", "192.168.0.0/24"]
}
# Object variable
variable "web_server_config" {
description = "Web server configuration"
type = object({
instance_type = string
volume_size = number
ami_id = string
})
default = {
instance_type = "t3.medium"
volume_size = 50
ami_id = "ami-0c55b159cbfafe1f0"
}
}
# Tuple variable
variable "config_values" {
description = "Configuration values"
type = tuple([string, number, bool])
default = ["value1", 42, true]
}
variable "environment" {
description = "Deployment environment"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}
variable "instance_type" {
description = "EC2 instance type"
type = string
validation {
condition = can(regex("^t[23]\\..*", var.instance_type))
error_message = "Instance type must be t2 or t3 family."
}
}
variable "port" {
description = "Port number"
type = number
validation {
condition = var.port > 0 && var.port < 65536
error_message = "Port must be between 1 and 65535."
}
}
# In main.tf
variable "region" {
description = "AWS region"
type = string
default = "us-east-1"
}
variable "vpc_cidr" {
description = "VPC CIDR block"
type = string
default = "10.0.0.0/16"
}
variable "instance_type" {
description = "EC2 instance type"
type = string
default = "t3.micro"
}
variable "environment" {
description = "Environment name"
type = string
}
# Using variables in resources
provider "aws" {
region = var.region
}
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
tags = {
Name = "${var.environment}-vpc"
Environment = var.environment
}
}
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = var.instance_type
count = var.instance_count
tags = {
Name = "${var.environment}-web-${count.index + 1}"
}
}

Variables can be provided from multiple sources, in order of precedence:

┌─────────────────────────────────────────────────────────────────────────────┐
│ Variable Precedence (Highest to Lowest) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. Command line: -var='name=value' ← Highest priority │
│ 2. Command line: -var-file=file.tfvars │
│ 3. Environment variables: TF_VAR_name │
│ 4. terraform.tfvars file │
│ 5. terraform.tfvars.json file │
│ 6. *.auto.tfvars file │
│ 7. Default value in variable declaration ← Lowest priority │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
terraform.tfvars
environment = "production"
region = "us-east-1"
instance_type = "t3.small"
# Or JSON format: terraform.tfvars.json
{
"environment": "production",
"region": "us-east-1",
"instance_type": "t3.small"
}
# environment.tfvars - environment-specific
environment = "staging"
instance_type = "t3.medium"
# prod.tfvars
environment = "prod"
instance_type = "t3.large"
Terminal window
# Set as environment variables
export TF_VAR_region="us-west-2"
export TF_VAR_environment="production"
export TF_VAR_instance_type="t3.large"
# Terraform automatically reads these
terraform plan
Terminal window
# Single variable
terraform apply -var="environment=prod"
# Multiple variables
terraform apply -var="environment=prod" -var="region=us-west-2"
# Variable file
terraform apply -var-file="prod.tfvars"
# Override default
terraform apply -var="instance_type=t3.large" -var-file="prod.tfvars"

Output values expose values from your Terraform configuration.

┌─────────────────────────────────────────────────────────────────────────────┐
│ Output Values Concept │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Output Declaration │ │
│ │ │ │
│ │ output "name" { │ │
│ │ description = "Explanation" │ │
│ │ value = resource.attribute │ │
│ │ sensitive = false # Optional │ │
│ │ depends_on = [...] # Optional │ │
│ │ } │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │
│ Use cases: │
│ ✓ Pass outputs to other configurations │
│ ✓ Display information after apply │
│ ✓ Share data between modules │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
# Basic output
output "instance_id" {
description = "ID of the EC2 instance"
value = aws_instance.web.id
}
# Multiple outputs
output "vpc_info" {
description = "VPC information"
value = {
id = aws_vpc.main.id
cidr = aws_vpc.main.cidr_block
subnets = aws_subnet.public[*].id
}
}
# Sensitive output (won't display in console)
output "database_password" {
description = "Database password"
value = aws_db_instance.main.password
sensitive = true
}
# Conditional output
output "elb_dns" {
description = "Load balancer DNS"
value = aws_lb.web.dns_name
# Only show if load balancer exists
}
# Output with depends_on
output "instance_ip" {
description = "Public IP of instance"
value = aws_instance.web.public_ip
depends_on = [aws_instance.web]
}

Local values assign a name to an expression, making configurations more readable.

┌─────────────────────────────────────────────────────────────────────────────┐
│ Local Values Concept │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Locals Block │ │
│ │ │ │
│ │ locals { │ │
│ │ name = expression │ │
│ │ } │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │
│ Benefits: │
│ ✓ Reduce repetition │
│ ✓ Improve readability │
│ ✓ Calculate derived values │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
# Basic locals
locals {
environment = "production"
project_name = "myapp"
# Common tags applied to all resources
common_tags = {
Project = local.project_name
Environment = local.environment
ManagedBy = "Terraform"
}
}
# Using locals in resources
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
tags = local.common_tags
}
resource "aws_s3_bucket" "data" {
bucket = "${local.project_name}-data-${var.environment}"
tags = local.common_tags
}
# Complex expressions in locals
locals {
# Merge maps
tags = merge(var.custom_tags, {
Environment = var.environment
Project = "MyApp"
})
# Conditional values
instance_type = var.environment == "prod" ? "t3.large" : "t3.micro"
# String interpolation
name_prefix = "${var.project}-${var.environment}"
# List operations
subnet_count = length(var.availability_zones)
}
# Using functions in locals
locals {
# String functions
lowercase_name = lower(var.Name)
sanitized_name = replace(var.Name, "/[^a-z0-9-]/", "-")
# Map functions
environment_map = {
dev = { instance_type = "t3.micro", replicas = 1 }
staging = { instance_type = "t3.small", replicas = 2 }
prod = { instance_type = "t3.large", replicas = 3 }
}
selected_config = local.environment_map[var.environment]
}
variables.tf
variable "project" {
description = "Project name"
type = string
}
variable "environment" {
description = "Environment (dev/staging/prod)"
type = string
default = "dev"
}
variable "region" {
description = "AWS region"
type = string
default = "us-east-1"
}
variable "vpc_cidr" {
description = "VPC CIDR block"
type = string
default = "10.0.0.0/16"
}
variable "instance_type" {
description = "EC2 instance type"
type = string
default = "t3.micro"
}
variable "instance_count" {
description = "Number of instances"
type = number
default = 1
}
# locals.tf
locals {
name_prefix = "${var.project}-${var.environment}"
common_tags = {
Project = var.project
Environment = var.environment
ManagedBy = "Terraform"
}
}
# outputs.tf
output "vpc_id" {
description = "ID of the VPC"
value = aws_vpc.main.id
}
output "instance_ids" {
description = "IDs of EC2 instances"
value = aws_instance.web[*].id
}
output "instance_ips" {
description = "Public IPs of EC2 instances"
value = aws_instance.web[*].public_ip
}
# main.tf
provider "aws" {
region = var.region
}
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
tags = local.common_tags
}
resource "aws_instance" "web" {
count = var.instance_count
ami = "ami-0c55b159cbfafe1f0"
instance_type = var.instance_type
subnet_id = aws_subnet.main[0].id
tags = merge(local.common_tags, {
Name = "${local.name_prefix}-web-${count.index + 1}"
})
}
resource "aws_subnet" "main" {
count = var.instance_count > 1 ? 2 : 1
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index)
availability_zone = var.region == "us-east-1" ? "us-east-1${["a", "b"][count.index]}" : "us-west-2${["a", "b"][count.index]}"
tags = local.common_tags
}

In this chapter, you learned:

  • Input Variables: Types (string, number, bool, list, map, object), validation
  • Variable Sources: CLI, files, environment variables, defaults
  • Output Values: Exposing resource attributes, sensitive outputs
  • Local Values: Reducing repetition, improving readability