Skip to main content

Managing Local Values

1. Declaring Local Values

Property Values Description
local.name string Name of the local value
value any Value to be stored locally

Example: Declaring a local value

locals {
  instance_type = "t3.micro"
  region        = "us-west-2"
}

Example: Using a local value in a resource

resource "aws_instance" "web" {
  ami           = "ami-12345678"
  instance_type = local.instance_type
  region        = local.region
}

2. Computing Derived Values

Property Description Example
count Number of instances to create count = 2
for_each Creates instances for each key-value pair in a map or set for_each = { env1 = "prod", env2 = "dev" }
index Index of the current instance in a count loop index = 0
each.key Key of the current instance in a for_each loop each.key = "env1"
each.value Value of the current instance in a for_each loop each.value = "prod"

Example: Using for_each to create multiple resources

resource "aws_instance" "web" {
  for_each = {
    us-west-1 = "t2.micro"
    us-east-1 = "t2.small"
  }

  ami           = "ami-12345678"
  instance_type = each.value
  region        = each.key
}

Example: Using count to create multiple resources

resource "aws_security_group" "web" {
  count = 2

  name        = "web-${count.index}"
  description = "Security group for web server ${count.index}"
}
Note: for_each is preferred over count when the instances are distinct and have meaningful keys.
Warning: Changing the count or for_each value will cause Terraform to recreate resources.

3. Referencing Local Values

Reference Syntax Description Example
local.<name> Reference to a local value defined in the same configuration local.my_variable

Example: Referencing Local Values in Variables

variable "instance_type" {
  description = "Type of instance to launch"
  default     = local.default_instance_type
}

locals {
  default_instance_type = "t3.micro"
}

Example: Using Local Values in Resource Configuration

resource "aws_instance" "web" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = local.instance_type

  tags = {
    Name = "web-server"
    Env  = local.environment
  }
}

locals {
  instance_type   = "t3.micro"
  environment     = "production"
}
Note: Local values can be referenced in any expression where a variable or attribute is expected, including within other local value definitions.

4. Using Locals for DRY

Using locals blocks in Terraform helps avoid repetition and makes configurations more maintainable by defining reusable values.

Property Description Usage Example
locals.block Defines a block of local values that can be referenced throughout the configuration.
locals {
  region = "us-west-2"
  environment = "prod"
}
local.value.reference Accesses a local value defined in the locals block using local.<name>.
resource "aws_instance" "web" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t3.micro"
  availability_zone = local.region
}

Example: Reusing Region in Multiple Resources

locals {
  region = "us-east-1"
}

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
  tags = {
    Name = "main-vpc"
  }
  region = local.region
}

resource "aws_subnet" "main" {
  vpc_id = aws_vpc.main.id
  cidr_block = "10.0.1.0/24"
  availability_zone = local.region
}
Note: Locals are not variables in the traditional sense; they're computed at plan time and do not support dynamic values or functions like count or for_each.

5. Combining Multiple Expressions

Example: Concatenating Strings

resource "aws_instance" "web" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t2.micro"

  tags = {
    Name = "web-server-" + var.environment
  }
}
Expression Description Result
var.environment + "-web" String concatenation "dev-web"
format("%s-%d", var.environment, 1) Formatting with placeholders "dev-1"
Note: Use + operator for simple string concatenation. For more complex formatting, use format().

Example: Combining Lists

variable "allowed_ports" {
  type    = list(number)
  default = [80, 443]
}

variable "additional_ports" {
  type    = list(number)
  default = [22, 3306]
}

resource "aws_security_group" "web_sg" {
  name        = "web-sg"
  description = "Allow traffic on allowed and additional ports"

  ingress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  dynamic "ingress" {
    for_each = concat(var.allowed_ports, var.additional_ports)
    content {
      from_port   = ingress.value
      to_port     = ingress.value
      protocol    = "tcp"
    }
  }
}
Operation Description Result
concat(var.allowed_ports, var.additional_ports) Merge two lists [80, 443, 22, 3306]
slice(var.list, 0, 2) Extract a portion of a list [80, 443]
Note: The concat() function combines multiple lists into one. Use slice() to extract a subset of list elements.

Example: Conditional Expression with Multiple Values

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

locals {
  instance_type = var.environment == "prod" ? "t3.xlarge" : "t2.micro"
  tags          = var.environment == "prod" ? {
    Name        = "production-server"
    Environment = "production"
  } : {
    Name        = "development-server"
    Environment = "development"
  }
}

resource "aws_instance" "web" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = local.instance_type

  tags = local.tags
}
Expression Description Result
var.environment == "prod" ? "t3.xlarge" : "t2.micro" Conditional assignment "t2.micro"
var.environment == "prod" ? { Name = "production-server", Environment = "production" } : { Name = "development-server", Environment = "development" } Conditional object creation { Name = "development-server", Environment = "development" }
Note: The ternary operator (?) allows conditional logic in expressions. It evaluates a condition and returns one of two values based on the result.

6. Using Locals with Functions

Function Description Example
local.value Access a local value defined in the configuration. local.value = "example"
length() Returns the length of a string or list. Example: Using length() with locals length(local.my_list)
upper() Converts a string to uppercase. Example: Using upper() with locals upper(local.my_string)
lower() Converts a string to lowercase. Example: Using lower() with locals lower(local.my_string)
split() Splits a string into a list based on a delimiter. Example: Using split() with locals split(",", local.my_string)
join() Joins a list into a string with a delimiter. Example: Using join() with locals join(",", local.my_list)

7. Organizing Locals by Purpose

Local Name Purpose Usage Notes
project_name Project identifier local.project_name = "my-terraform-project" Used to namespace resources and logs
environment Deployment environment local.environment = "production" Allows for environment-specific configuration
region Cloud region local.region = "us-west-2" Used for resource location consistency
vpc_cidr VPC network range local.vpc_cidr = "10.0.0.0/16" Centralized network configuration

Example: Organizing locals in modules

locals {
  project_name = "my-terraform-project"
  environment  = "production"
  region       = "us-west-2"
  vpc_cidr     = "10.0.0.0/16"
}

module "network" {
  source = "./network-module"
  project_name = local.project_name
  environment  = local.environment
  region       = local.region
}
Note: Grouping locals by purpose improves readability and maintainability of Terraform configurations.

8. Comparing Locals vs Variables

Feature Locals Variables
Scope local.<name> var.<name>
Reassignment Not allowed once defined Can be overridden via CLI or TFVars
Declaration Within locals { } block Within variable "name" { } block
Usage Used for internal computations Used to pass external inputs
Default Values Yes, via default Yes, via default
Validation No built-in validation Yes, via validation

When to Use Which?

  • Use Locals for computed values that are internal to the configuration and do not change.
  • Use Variables for values that can be changed externally, such as environment-specific settings or user inputs.

9. Using Locals in Modules

Property Description Usage
local.name Defines a local value within a module locals { instance_type = "t3.micro" }
module.module_name.local.value Accesses a local value from a child module module.my_module.local.instance_type

Example: Defining and Using Locals in Modules

module "ec2_instance" {
  source = "./ec2_module"
  instance_type = local.instance_type
}

locals {
  instance_type = "t3.micro"
}
Note: Locals in modules are useful for defining values that are reused across multiple resources or other modules.

10. Referencing Locals in Outputs

Reference Description Example
local.<name> References a local variable defined in the configuration
output "instance_id" {
  value = local.instance_id
}

Example: Outputting a Local Value

locals {
  instance_id = "i-1234567890abcdef0"
}

output "instance_id" {
  value = local.instance_id
}

Was this article helpful?