> ## Content Index
> Fetch the complete content index at: https://linuxhandbook.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Chapter 3: Terraform Variables and Locals
- URL: https://linuxhandbook.com/courses/terraform/terraform-variables-locals/
- Published: 2025-11-28T10:05:51.000Z
- Updated: 2025-11-28T10:05:51.000Z
- Description: Hardcoding values works for demos, not production. Variables make your code flexible. Locals make it DRY (Don’t Repeat Yourself).
- Author: Akhilesh Mishra
- Tags: Terraform, #lessons-col, #lesson-duration-20m

## 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 Variable and other values in Terraform.](https://linuxhandbook.com/content/images/2025/11/terraform-apply-variable.png)

Apply Variable

Always 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 Check Terraform](https://linuxhandbook.com/content/images/2025/11/validation-check.png)

Validation Check

## Sensitive 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):

1. Command line: `-var="key=value"`
2. `*.auto.tfvars` files (alphabetical order)
3. `terraform.tfvars` file
4. Environment variables: `TF_VAR_name`
5. 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.