TerraformPilot

Terraform

Terraform Locals vs Variables - When to Use Each

Understand the difference between Terraform locals and variables. Step-by-step guide with code examples and best practices for Terraform projects.

LLuca Berton1 min read

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.

#Terraform#Best Practices#Infrastructure as Code

Share this article