Chapter 3: Terraform Variables and Locals
· Blogger · 11/28/25 10:05 AM
Fri, 28 Nov 2025 15:35:51 +0530
Basic Variable Types
Terraform has three basic types: string, number, and bool.
variable "name" { type = string description = "User name" default = "World" } variable "counts" { type = number default = 5 } variable "enabled" { type = bool default = true } Use them:
resource "local_file" "example" { content = "Hello, ${var.name}! Count: ${var.counts}, Enabled: ${var.enabled}" filename = "output.txt" } 🚧You cannot use reserved words like count as variable name.Change values:
terraform apply -var="name=Alice" -var="counts=10" Apply VariableAlways add description. Future you will thank you.
Advanced Variable Types
Real infrastructure needs complex data structures.
Lists
Ordered collections of values:
variable "availability_zones" { type = list(string) default = ["us-west-2a", "us-west-2b", "us-west-2c"] } Access elements:
locals { first_az = var.availability_zones[0] # "us-west-2a" all_zones = join(", ", var.availability_zones) } Use in resources:
resource "aws_subnet" "public" { count = length(var.availability_zones) availability_zone = var.availability_zones[count.index] # ... other config } Maps
Key-value pairs:
variable "instance_types" { type = map(string) default = { dev = "t2.micro" prod = "t2.large" } } Access values:
resource "aws_instance" "app" { instance_type = var.instance_types["prod"] # Or with lookup function instance_type = lookup(var.instance_types, var.environment, "t2.micro") } Objects
Structured data with different types:
variable "database_config" { type = object({ instance_class = string allocated_storage = number multi_az = bool backup_retention = number }) default = { instance_class = "db.t3.micro" allocated_storage = 20 multi_az = false backup_retention = 7 } } Use in resources:
resource "aws_db_instance" "main" { instance_class = var.database_config.instance_class allocated_storage = var.database_config.allocated_storage multi_az = var.database_config.multi_az backup_retention_period = var.database_config.backup_retention } List of Objects
The power combo - multiple structured items:
variable "servers" { type = map(object({ size = string disk = number })) default = { web-1 = { size = "t2.micro", disk = 20 } web-2 = { size = "t2.small", disk = 30 } } } resource "aws_instance" "servers" { for_each = var.servers instance_type = each.value.size tags = { Name = each.key } root_block_device { volume_size = each.value.disk } } Sets and Tuples
Set - Like list but unordered and unique:
variable "allowed_ips" { type = set(string) default = ["10.0.0.1", "10.0.0.2"] } Tuple - Fixed-length list with specific types:
variable "server_config" { type = tuple([string, number, bool]) default = ["t2.micro", 20, true] } Rarely used. Stick with lists and maps for most cases.
Variable Validation
Add rules to validate input:
variable "environment" { type = string description = "Environment name" validation { condition = contains(["dev", "staging", "prod"], var.environment) error_message = "Environment must be dev, staging, or prod." } } variable "instance_count" { type = number default = 1 validation { condition = var.instance_count >= 1 && var.instance_count <= 10 error_message = "Instance count must be between 1 and 10." } } Catches errors before Terraform runs.
Validation CheckSensitive Variables
Mark secrets as sensitive:
variable "db_password" { type = string sensitive = true } Won’t appear in logs or plan output. Still stored in state though (encrypt your state!).
Variable Precedence
Multiple ways to set variables. Terraform picks in this order (highest to lowest):
Command line: -var="key=value" *.auto.tfvars files (alphabetical order) terraform.tfvars file Environment variables: TF_VAR_name Default value in variable block Setting Variables with Files
Create terraform.tfvars:
environment = "prod" instance_type = "t2.large" database_config = { instance_class = "db.t3.large" allocated_storage = 100 multi_az = true backup_retention = 30 } Run terraform apply - picks up values automatically
Or environment-specific files:
# dev.tfvars environment = "dev" instance_type = "t2.micro" terraform apply -var-file="dev.tfvars" Locals: Computed Values
Variables are inputs. Locals are calculated values you use internally.
variable "project_name" { type = string default = "myapp" } variable "environment" { type = string default = "dev" } locals { resource_prefix = "${var.project_name}-${var.environment}" common_tags = { Project = var.project_name Environment = var.environment ManagedBy = "Terraform" } is_production = var.environment == "prod" backup_count = local.is_production ? 3 : 1 } resource "aws_s3_bucket" "data" { bucket = "${local.resource_prefix}-data" tags = local.common_tags } Use var. for variables, local. for locals.
Outputs
Display values after apply:
output "bucket_name" { description = "Name of the S3 bucket" value = aws_s3_bucket.data.id } output "is_production" { value = local.is_production } output "db_endpoint" { value = aws_db_instance.main.endpoint sensitive = true # Don't show in logs } View outputs:
terraform output terraform output bucket_name Real-World Example
variable "environment" { type = string validation { condition = contains(["dev", "staging", "prod"], var.environment) error_message = "Must be dev, staging, or prod." } } variable "app_config" { type = object({ instance_type = string min_size = number }) } locals { common_tags = { Environment = var.environment ManagedBy = "Terraform" } # Override for production min_size = var.environment == "prod" ? 3 : var.app_config.min_size } resource "aws_autoscaling_group" "app" { name = "myapp-${var.environment}-asg" min_size = local.min_size desired_capacity = local.min_size tags = [ for key, value in local.common_tags : { key = key value = value propagate_at_launch = true } ] } Quick Reference
Basic types:
variable "name" { type = string } variable "count" { type = number } variable "enabled" { type = bool } Complex types:
variable "zones" { type = list(string) } variable "types" { type = map(string) } variable "config" { type = object({ name = string, size = number }) } variable "servers" { type = map(object({ size = string, disk = number })) } Validation:
validation { condition = contains(["dev", "prod"], var.env) error_message = "Must be dev or prod." } Locals and Outputs:
locals { name = "${var.project}-${var.env}" } output "result" { value = aws_instance.app.id, sensitive = true } Variables make your code flexible. Complex types model real infrastructure. Locals keep things DRY. Outputs share information.
With variables and locals in your toolkit, you now know how to make your Terraform code flexible and maintainable. But where does Terraform store the information about what it created? And how does it connect to AWS, Azure, or other cloud providers? That’s what we’ll explore next with state management and providers.
- Read more...
- 0 comments
- 7 views
-