Input Variables
Variables are parameters that allow you to pass values into Terraform configurations without modifying the source code. They make configurations reusable and customizable.
Variable Declaration
variable "instance_type" {
description = "Size of EC2 instance"
type = string
default = "t2.micro"
}Components:
description: Documentation explaining the variabletype: What kind of value (string, number, bool, list, map, object)default: Default value if not providedsensitive: Hide from logs (for passwords, keys)validation: Custom validation rules
Variable Types
| Type | Example | Use Case |
|---|---|---|
| string | "t2.micro" | Single text value |
| number | 3 | Numeric value |
| bool | true | True/false flag |
| list | ["az1", "az2"] | Ordered collection |
| map | Key-value pairs | |
| object | Typed collection | |
| tuple | ["string", 1] | Fixed-size mixed types |
| any | (any value) | Flexible, not recommended |
String Variable
variable "environment" {
description = "Environment name"
type = string
default = "dev"
}
# Usage:
resource "aws_instance" "web" {
tags = {
Environment = var.environment
}
}List Variable
variable "availability_zones" {
description = "Availability zones for resources"
type = list(string)
default = ["us-east-1a", "us-east-1b"]
}
# Usage:
resource "aws_subnet" "private" {
count = length(var.availability_zones)
availability_zone = var.availability_zones[count.index]
# ...
}Map Variable
variable "tags" {
description = "Common tags for all resources"
type = map(string)
default = {
Team = "Platform"
Environment = "Production"
CostCenter = "Engineering"
}
}
# Usage:
resource "aws_instance" "web" {
tags = var.tags
}Object Variable
variable "db_config" {
description = "Database configuration"
type = object({
name = string
engine = string
instance_type = string
storage_size = number
})
default = {
name = "myapp"
engine = "mysql"
instance_type = "db.t3.micro"
storage_size = 20
}
}
# Usage:
resource "aws_db_instance" "main" {
db_name = var.db_config.name
engine = var.db_config.engine
identifier = var.db_config.name
}Variable Validation
variable "instance_count" {
description = "Number of instances"
type = number
validation {
condition = var.instance_count > 0 && var.instance_count <= 10
error_message = "Instance count must be between 1 and 10"
}
}
variable "environment" {
description = "Environment"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod"
}
}Sensitive Variables
variable "db_password" {
description = "Database password"
type = string
sensitive = true # Don't show in logs
}
variable "api_key" {
description = "API key"
type = string
sensitive = true
}
# Usage:
resource "aws_db_instance" "main" {
password = var.db_password
}Providing Variable Values
Method 1: terraform.tfvars
instance_type = "t2.small"
environment = "staging"
region = "us-west-2"
Method 2: Command line
terraform plan -var="instance_type=t2.small" -var="environment=staging"Method 3: Environment variables
export TF_VAR_instance_type=t2.small
export TF_VAR_environment=staging
terraform planMethod 4: .auto.tfvars files
# dev.auto.tfvars
instance_type = "t2.micro"
environment = "dev"
# prod.auto.tfvars
instance_type = "t3.xlarge"
environment = "prod"
Output Values
Outputs extract and display values from your infrastructure, similar to return values in programming. They're useful for showing important information after apply.
Output Declaration
output "instance_public_ip" {
description = "Public IP of web server"
value = aws_instance.web.public_ip
}Components:
description: Document what the output showsvalue: The value to outputsensitive: Hide from logs (passwords, keys)depends_on: Explicit dependency
Simple Outputs
# Single value
output "website_url" {
description = "URL to access website"
value = "http://${aws_instance.web.public_ip}"
}
# List
output "security_group_ids" {
description = "Security group IDs"
value = aws_security_group.web[*].id
}
# Map
output "instance_details" {
description = "Instance information"
value = {
id = aws_instance.web.id
ip = aws_instance.web.public_ip
dns_name = aws_instance.web.public_dns
}
}Complex Outputs
output "load_balancer_endpoint" {
description = "ALB endpoint"
value = {
dns_name = aws_lb.main.dns_name
zone_id = aws_lb.main.zone_id
target_groups = [
for tg in aws_lb_target_group.main : {
arn = tg.arn
name = tg.name
}
]
}
}Sensitive Outputs
output "database_password" {
description = "Database password"
value = random_password.db.result
sensitive = true # Don't display in console
}
# To view: terraform output -json database_passwordConditional Outputs
variable "enable_monitoring" {
type = bool
}
output "cloudwatch_dashboard" {
description = "CloudWatch dashboard URL"
value = var.enable_monitoring ? aws_cloudwatch_dashboard.main.dashboard_body : null
}Output with Dependencies
output "api_endpoint" {
description = "API endpoint"
value = aws_api_gateway_deployment.main.invoke_url
depends_on = [
aws_api_gateway_integration.lambda
]
}Accessing Outputs
After apply:
terraform output # Show all outputs
terraform output instance_public_ip # Show specific output
terraform output -json # JSON formatIn other configurations:
# reference_stack/main.tf
data "terraform_remote_state" "main" {
backend = "s3"
config = {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
}
}
resource "aws_route53_record" "web" {
zone_id = aws_route53_zone.main.zone_id
name = "api.example.com"
type = "A"
alias {
name = data.terraform_remote_state.main.outputs.load_balancer_dns
zone_id = data.terraform_remote_state.main.outputs.load_balancer_zone_id
evaluate_target_health = true
}
}Variable Best Practices
| Practice | Example | Benefit |
|---|---|---|
| Use descriptions | description = "..." | Self-documenting code |
| Set types explicitly | type = list(string) | Validate inputs |
| Use validation blocks | validation { condition = ... } | Catch errors early |
| Default for dev | default = "t2.micro" | Quick testing |
| Mark sensitive data | sensitive = true | Security |
| Use terraform.tfvars | Create per environment | Easy multi-environment |
| Organize by layer | Core, networking, app | Maintainability |
| Use modules | module "networking" {} | Reusable components |
Output Best Practices
| Practice | Example | Benefit |
|---|---|---|
| Document everything | description = "..." | Clear what matters |
| Show computed values | value = aws_lb.main.dns_name | Easy reference |
| Group related outputs | Map or object type | Organized results |
| Use depends_on when needed | depends_on = [...] | Correct ordering |
| Hide sensitive data | sensitive = true | Security |
| Test outputs | terraform output | Verify before use |
| Export to CI/CD | terraform output -json | Automation |
Common Patterns
Multi-Environment Setup
variable "environment" {
type = string
}
variable "instance_type" {
type = map(string)
default = {
dev = "t2.micro"
staging = "t2.small"
prod = "t3.large"
}
}
resource "aws_instance" "main" {
instance_type = var.instance_type[var.environment]
}Feature Flags
variable "enable_monitoring" {
type = bool
default = true
}
variable "enable_backup" {
type = bool
default = true
}
resource "aws_cloudwatch_log_group" "main" {
count = var.enable_monitoring ? 1 : 0
name = "/aws/lambda/main"
retention_in_days = 7
}Exposing Computed Values
resource "aws_lb" "main" {
# ...
}
output "load_balancer_dns" {
description = "DNS name of load balancer"
value = aws_lb.main.dns_name
}
output "resources_created" {
description = "Summary of created resources"
value = {
lb_dns = aws_lb.main.dns_name
lb_zone = aws_lb.main.zone_id
timestamp = timestamp()
}
}