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: 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. | |
| local.value.reference | Accesses a local value defined in the locals block using local.<name>. |
|
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 | |