Terraform Variables vs. Locals: Best Practices, Examples, and Use Cases

Terraform is an essential tool for managing infrastructure as code, and one of its core features is the ability to use variables and locals. Understanding when and how to use them effectively can improve the readability, reusability, and maintainability of your Terraform configurations.


Terraform Variables

Variables in Terraform allow you to parameterize your configurations. This makes your code flexible and reusable across multiple environments or configurations. Variables are defined using the variable block and can be provided through:

  • terraform.tfvars or *.auto.tfvars files
  • Environment variables
  • CLI input during runtime
Example: Using Variables
variable "region" {
  description = "The AWS region to deploy resources."
  type        = string
  default     = "us-west-2"
}

variable "instance_count" {
  description = "Number of instances to create."
  type        = number
  default     = 2
}

resource "aws_instance" "example" {
  ami           = "ami-12345678"
  instance_type = "t2.micro"
  count         = var.instance_count
  tags = {
    Name = "Terraform-Instance"
  }
  availability_zone = "${var.region}a"
}

Best Practices for Variables
  1. Use Descriptive Names: Make variable names meaningful to enhance readability.
  2. Define Defaults for Common Values: Use defaults for values that do not change often.
  3. Secure Sensitive Variables: Mark sensitive variables (e.g., secrets, passwords) as sensitive = true.
  4. Provide Descriptions: Add descriptions to variables for better documentation.

Terraform Locals

Locals are expressions that define reusable values calculated from input variables or resource attributes. They are evaluated during the plan phase and are read-only within the configuration.

Example: Using Locals
variable "environment" {
  type    = string
  default = "production"
}

variable "project_name" {
  type    = string
  default = "my-app"
}

locals {
  resource_name_prefix = "${var.project_name}-${var.environment}"
}

resource "aws_s3_bucket" "example" {
  bucket = "${local.resource_name_prefix}-bucket"
  acl    = "private"
}

Here, locals.resource_name_prefix combines project_name and environment to ensure consistent naming across resources.

Best Practices for Locals
  1. Use for Computed Values: Prefer locals for calculated values or intermediate variables to reduce duplication.
  2. Group Related Values: Combine related logic into locals for better organization.
  3. Avoid Overuse: Overusing locals for trivial values can make your code harder to follow.

Key Differences Between Variables and Locals

FeatureVariablesLocals
PurposeUser-defined inputsComputed or intermediate values
ScopeInput to the configurationRead-only within the configuration
FlexibilityDefined externally (via files or CLI)Defined and used only within the same file
Use CaseCustomizing configurations per environmentReducing redundancy and improving clarity

Common Use Cases

  • Variables:
    • Parameterizing deployment environments (e.g., dev, staging, prod).
    • Defining resource counts, region, or instance types.
  • Locals:
    • Creating a consistent naming convention.
    • Simplifying complex logic using derived values.
    • Grouping values such as tagging information.
Example: Combining Variables and Locals
variable "tags" {
  type = map(string)
  default = {
    Environment = "prod"
    Team        = "devops"
  }
}

locals {
  merged_tags = merge(var.tags, { CreatedBy = "Terraform" })
}

resource "aws_instance" "example" {
  ami           = "ami-12345678"
  instance_type = "t2.micro"
  tags          = local.merged_tags
}

Here, locals.merged_tags combines predefined tags with additional information, ensuring all resources share consistent metadata.


Final Thoughts and Best Practices

  1. Balance Variables and Locals: Use variables for external inputs and locals for internal computations.
  2. Organize Variables and Locals: Place them in separate files (variables.tf and locals.tf) for better modularity.
  3. Keep it Simple: Avoid over-engineering; use only as many variables or locals as necessary.

By understanding the strengths and limitations of variables and locals, you can write more maintainable and efficient Terraform configurations. Happy Terraforming!