Terraform & IaC

Don't Repeat Yourself: Local Values

Lesson 7 of 14 · 8 min · Intermediate

A local value assigns a name to an expression so you can use it multiple times within a module without repeating code. Unlike input variables, locals cannot be overridden from outside — they are computed internally to enforce naming rules, merge common tags, and simplify complex expressions.

What is a Local Value?

Think of Input Variables as function parameters that someone else passes in, and Local Values as internal local variables created inside the function body to store intermediate calculations.

When to Use Local Values

  • Standardized Naming: Concatenating "${var.env}-${var.app_name}-${var.region}" once instead of typing it on 20 resources.
  • Common Tag Sets: Enforcing mandatory compliance tags (Owner, Environment, CostCenter, ManagedBy) across all cloud assets.
  • Complex Calculations: Storing ternary conditions or formatting CIDR blocks cleanly.

Scoped to Current Module

Locals are strictly internal. A parent module or CLI argument cannot override or read a child module's locals block. This encapsulates business logic safely.

Reference Any Variable or Resource

Locals can reference variables (var.foo), other locals (local.bar), and exported resource attributes (aws_vpc.main.id).

Declaring & Referencing Locals

locals.tf
locals {
  service_name = "billing-api"
  owner        = "shan-devops"
  prefix       = "${var.environment}-${local.service_name}"
  
  is_prod      = var.environment == "production" ? true : false
  instance_type= local.is_prod ? "m5.large" : "t3.micro"
}
main.tf
resource "aws_instance" "web" {
  ami           = "ami-0123456789abcdef0"
  instance_type = local.instance_type

  tags = {
    Name = "${local.prefix}-web-server"
  }
}

Notice the reference syntax: You declare with locals { ... } (plural), but when referencing you use local.name (singular).

Enterprise Tagging with merge()

Every enterprise cloud governance policy requires tags for cost tracking, auditing, and ownership. Defining a central common_tags map inside a local block and combining it with resource-specific tags via the merge() function is the gold standard.

Single Place to Update

If finance requests a new CostCenter = "CC-904" tag across 50 resources, you add one line in locals.tf and Terraform updates every resource cleanly on next apply.

main.tf
locals {
  common_tags = {
    Project     = "ECommerce-Portal"
    Environment = var.environment
    ManagedBy   = "Terraform"
    Owner       = "Shan DevOps"
  }
}

resource "aws_s3_bucket" "app_data" {
  bucket = "shan-app-storage-${var.environment}"

  tags = merge(local.common_tags, {
    Name        = "app-storage-bucket"
    DataPrivacy = "Confidential"
  })
}

Complex Expressions & String Manipulation

locals.tf
locals {
  # List slicing and joining
  azs             = ["ap-south-1a", "ap-south-1b", "ap-south-1c"]
  active_azs      = slice(local.azs, 0, var.az_count)

  # Dynamic S3 bucket naming (lower-cased and sanitized)
  bucket_name     = lower(replace("${var.company}-${var.project}-${var.environment}", "_", "-"))

  # Conditional count
  enable_bastion  = var.environment == "prod" ? 1 : 0
}

Clean Resource Blocks

Without locals, resource blocks become bloated with nested functions like lower(replace(...)) or complex ternary statements. Shifting computation into locals.tf keeps main.tf clean and declarative.

Debug with terraform console

You can test and evaluate local expressions interactively in the CLI using terraform console before applying changes.

Variables vs Locals vs Outputs vs Data

TypeSyntax PrefixWho Sets Value?Overridable from CLI?Primary Purpose
Input Variablevar.nameUser / CI/CD pipelineYesExternal parameters & environment tuning
Local Valuelocal.nameInternal module logicNoDRY expressions, naming rules, tag maps
Output Valueoutput.nameExported by resourceNoReturn values for CLI or parent modules
Data Sourcedata.type.nameCloud Provider APINoRead existing infrastructure external to code

Best Practices & Pitfalls to Avoid

✓ DO

  • Use locals for values referenced multiple times in the same module.
  • Use locals for common tag maps and standard naming prefixes.
  • Store locals in a dedicated locals.tf file when projects grow.

✗ DON'T

  • Don't create a local for every single hardcoded literal used only once.
  • Don't use locals when users need to customize the value per environment (use variables).
  • Avoid creating circular local dependencies (e.g. A references B, B references A).