Table of Contents

Introduction

Terraform locals and variables serve different purposes, but beginners often confuse them. This guide clarifies when to use each with practical examples.

Quick Comparison

FeatureVariablesLocals
PurposeAccept external inputCompute internal values
Set byUser/environmentConfiguration code
ScopeModule-wideModule-wide
OverrideYes (tfvars, CLI, env)No
Syntaxvar.namelocal.name

Variables - External Input

Variables accept input from outside your module:

variable "environment" {
  type    = string
  default = "dev"
}

variable "instance_count" {
  type    = number
  default = 1
}

Set values via:

terraform apply -var="environment=prod"

Or in terraform.tfvars:

environment    = "prod"
instance_count = 3

Locals - Computed Values

Locals are computed values used within your configuration:

locals {
  name_prefix = "${var.project}-${var.environment}"
  
  common_tags = {
    Project     = var.project
    Environment = var.environment
    ManagedBy   = "terraform"
  }
  
  is_production = var.environment == "prod"
  instance_type = local.is_production ? "t3.large" : "t3.micro"
}

When to Use Variables

Use variables when:

  • The value comes from outside the module
  • Different environments need different values
  • Users need to customize behavior
  • Modules need input from their callers
variable "region" {
  description = "AWS region"
  type        = string
}

variable "vpc_cidr" {
  description = "CIDR block for VPC"
  type        = string
  default     = "10.0.0.0/16"
}

When to Use Locals

Use locals when:

  • Computing derived values from variables
  • Avoiding repetition (DRY principle)
  • Complex expressions used multiple times
  • Internal logic that shouldn’t be externally configurable
locals {
  # Derived from variables - users shouldn't set these directly
  subnet_cidrs = [for i in range(3) : cidrsubnet(var.vpc_cidr, 8, i)]
  
  # Repeated expression - define once, use everywhere
  common_tags = merge(var.extra_tags, {
    Environment = var.environment
    Terraform   = "true"
  })
  
  # Conditional logic
  instance_type = var.environment == "prod" ? "m5.xlarge" : "t3.micro"
}

Anti-Patterns to Avoid

Don’t use variables for computed values

# BAD - this should be a local
variable "name_prefix" {
  default = "myapp-dev"  # Hardcoded, computed from other values
}

# GOOD
locals {
  name_prefix = "${var.app_name}-${var.environment}"
}

Don’t use locals for user input

# BAD - users can't override this
locals {
  region = "us-east-1"  # Should be configurable
}

# GOOD
variable "region" {
  type    = string
  default = "us-east-1"
}

Real-World Example

# variables.tf - What users configure
variable "project" { type = string }
variable "environment" { type = string }
variable "instance_count" { type = number; default = 1 }

# locals.tf - What the code computes
locals {
  name_prefix   = "${var.project}-${var.environment}"
  is_production = var.environment == "prod"
  
  common_tags = {
    Project     = var.project
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

# main.tf - Uses both
resource "aws_instance" "app" {
  count         = var.instance_count  # User input
  instance_type = local.is_production ? "t3.large" : "t3.micro"  # Computed
  tags          = merge(local.common_tags, { Name = "${local.name_prefix}-${count.index}" })
}

Hands-On Courses

Conclusion

Variables are for external input; locals are for internal computation. Using each correctly leads to cleaner, more maintainable Terraform code. When in doubt, ask: should the user set this value? If yes, use a variable. If no, use a local.