Local Values
Locals = ตัวแปรท้องถิ่นใน Terraform ที่ใช้ลด duplication และทำให้ code อ่านง่ายขึ้น — ไม่ใช่ input จากภายนอก
Locals Block
locals {
name_prefix = "${var.environment}-${var.project}"
common_tags = {
Environment = var.environment
Project = var.project
ManagedBy = "terraform"
}
}
ใช้ผ่าน local.<NAME>:
resource "aws_s3_bucket" "data" {
bucket = "${local.name_prefix}-data"
tags = local.common_tags
}
resource "aws_s3_bucket" "logs" {
bucket = "${local.name_prefix}-logs"
tags = local.common_tags
}
Locals vs Variables
| Aspect | variable | locals |
|---|---|---|
| Source | external (CLI, .tfvars, env) | internal (computed) |
| Type | typed | inferred |
| Override | ได้ | ไม่ได้ |
| เปลี่ยนตอน apply | ผ่าน input | recompute เอง |
| ใช้ทำอะไร | parameterize | DRY + readable |
Mental Model
- variable = "input parameter" ของ module/project
- locals = "private helper" คำนวณค่าใน module
Use Cases
1. Lessen Duplication
❌ ไม่ใช้ locals:
resource "aws_s3_bucket" "data" {
bucket = "${var.env}-${var.project}-data"
tags = {
Environment = var.env
Project = var.project
ManagedBy = "terraform"
}
}
resource "aws_s3_bucket" "logs" {
bucket = "${var.env}-${var.project}-logs"
tags = {
Environment = var.env
Project = var.project
ManagedBy = "terraform"
}
}
✅ ใช้ locals:
locals {
name_prefix = "${var.env}-${var.project}"
common_tags = {
Environment = var.env
Project = var.project
ManagedBy = "terraform"
}
}
resource "aws_s3_bucket" "data" {
bucket = "${local.name_prefix}-data"
tags = local.common_tags
}
resource "aws_s3_bucket" "logs" {
bucket = "${local.name_prefix}-logs"
tags = local.common_tags
}
2. Computed Values
variable "vpc_cidr" {
type = string
default = "10.0.0.0/16"
}
locals {
# คำนวณ subnet CIDR จาก VPC CIDR
public_subnets = [for i in range(2) : cidrsubnet(var.vpc_cidr, 8, i)]
private_subnets = [for i in range(2) : cidrsubnet(var.vpc_cidr, 8, i + 100)]
}
resource "aws_subnet" "public" {
count = length(local.public_subnets)
vpc_id = aws_vpc.main.id
cidr_block = local.public_subnets[count.index]
}
3. Conditional Logic
locals {
is_prod = var.environment == "prod"
instance_type = local.is_prod ? "t3.large" : "t3.micro"
backup_count = local.is_prod ? 30 : 7
multi_az = local.is_prod
}
resource "aws_db_instance" "main" {
instance_class = local.instance_type
backup_retention_period = local.backup_count
multi_az = local.multi_az
}
4. Transform Data
variable "users" {
type = list(object({
name = string
email = string
admin = bool
}))
}
locals {
# Convert list → map
user_map = { for u in var.users : u.name => u }
# Filter
admins = [for u in var.users : u if u.admin]
# Map (transform)
admin_emails = [for u in local.admins : u.email]
}
resource "aws_iam_user" "users" {
for_each = local.user_map
name = each.value.name
}
Multiple Locals Blocks
มีหลาย locals block ในไฟล์เดียวก็ได้ — Terraform merge ให้:
locals {
region = "ap-southeast-1"
}
locals {
full_name = "${local.region}-app"
}
→ access local.region และ local.full_name
ใช้แบ่งกลุ่ม locals ตาม theme เช่น:
locals {
# Naming
name_prefix = "${var.env}-${var.project}"
bucket_name = "${local.name_prefix}-data"
}
locals {
# Networking
vpc_cidr = "10.0.0.0/16"
public_subnets = [for i in range(2) : cidrsubnet(local.vpc_cidr, 8, i)]
}
locals {
# Tags
common_tags = {
Environment = var.env
ManagedBy = "terraform"
}
}
ตัวอย่าง Real-World
locals.tf
locals {
# Project metadata
project_name = "my-app"
environment = var.environment
region = data.aws_region.current.name
account_id = data.aws_caller_identity.current.account_id
# Naming
name_prefix = "${local.project_name}-${local.environment}"
bucket_name = "${local.name_prefix}-${local.account_id}-${local.region}"
# Tags (merge default with user tags)
common_tags = merge(
{
Project = local.project_name
Environment = local.environment
ManagedBy = "terraform"
Region = local.region
},
var.extra_tags
)
# Network (computed from VPC CIDR)
vpc_cidr = var.vpc_cidr
public_subnets = [for i in range(var.az_count) : cidrsubnet(local.vpc_cidr, 8, i)]
private_subnets = [for i in range(var.az_count) : cidrsubnet(local.vpc_cidr, 8, i + 100)]
# Conditional
is_prod = local.environment == "prod"
enable_deletion_protection = local.is_prod
backup_retention = local.is_prod ? 30 : 7
}
data "aws_region" "current" {}
data "aws_caller_identity" "current" {}
Anti-Patterns
# ❌ Locals ที่อ้างอิง resource attribute (slow, fragile)
locals {
vpc_id = aws_vpc.main.id # อันที่อ้าง .id ตรงๆ ดีกว่า
}
# ❌ Locals ที่คัดลอกค่ามาจาก variable
locals {
region = var.region # ใช้ var.region ตรงๆ ดีกว่า
}
# ❌ Locals ใหญ่เกินไป (อ่านยาก)
locals {
config = {
# 50+ keys ที่ลึกซ้อน
}
}
# ดีกว่าแยกเป็น object variable
สรุป
locals= private helper variable- ใช้ลด duplication + ทำ computed values + conditional logic
- ไม่รับ input จากภายนอก (ต่างจาก
variable) - มีหลาย
localsblock ในไฟล์เดียวได้ - หลีกเลี่ยง locals ที่ "ก็คือ variable เหมือนกัน" — ใช้
var.<x>ตรงๆ ดีกว่า
ต่อไป → Section 6: Outputs