1. 概要
この記事では、以下の内容を解説します。
localsとvariableの根本的な違い(「コード内で計算」vs「外部から受け取る」)- それぞれが適切なケースの判断基準と具体例
- 実務でよく見るアンチパターンと正しい使い方
localsとvariableを組み合わせた設計パターン
結論を先に述べます: variableは「Terraformの外部(CIやオペレーター)から変えたい値」に使い、localsは「コード内の計算や繰り返しを整理するため」に使います。この判断基準さえ押さえれば、迷うことはありません。
2. 一言で言うとどう違うか
| 比較項目 | variable | locals |
|---|---|---|
| 誰が値を決めるか | 外部(tfvars・CIの-var) | コード(自分) |
| 外から変更できるか | ✅ できる | ❌ できない |
| 式・計算を書けるか | ❌ 値のみ(式は不可) | ✅ 任意の式・計算結果 |
| 参照方法 | var.<名前> | local.<名前> |
| ブロック名 | variable | locals |
| 主な用途 | 環境・設定値の切り替え | 繰り返しの式に名前をつける |
| デフォルト値 | defaultで設定可能 | 常にコード内で定義 |
| 型制約 | typeで宣言可能 | 型制約なし |
3. variableを使うべきケース
variableはTerraformの外部から値を渡したい場合に使います。
ケース1: 環境ごとに値を変えたい
# variable: 環境名は外部から渡す(dev/stg/prdで変わる)
variable "environment" {
description = "デプロイ先の環境名(dev/stg/prd)"
type = string
validation {
condition = contains(["dev", "stg", "prd"], var.environment)
error_message = "environmentはdev/stg/prdのいずれかを指定してください。"
}
}
variable "instance_type" {
description = "EC2インスタンスタイプ"
type = string
default = "t3.micro"
}
# CIやオペレーターが外から渡す
terraform apply -var="environment=prd" -var="instance_type=t3.medium"
# またはtfvarsファイルで指定
# prd.tfvars
# environment = "prd"
# instance_type = "t3.medium"
terraform apply -var-file="prd.tfvars"
ケース2: モジュールに設定値を渡す
# modules/ec2/variables.tf
variable "project" {
description = "プロジェクト名(リソース名のプレフィックスに使用)"
type = string
}
variable "vpc_id" {
description = "リソースを配置するVPCのID"
type = string
}
variable "subnet_ids" {
description = "EC2を配置するサブネットIDのリスト"
type = list(string)
}
# 呼び出し元(ルートモジュール)
module "ec2" {
source = "./modules/ec2"
project = var.project # 呼び出し元のvariableを渡す
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnet_ids
}
4. localsを使うべきケース
localsはコード内の計算・繰り返しを整理するために使います。
ケース1: 繰り返し使う式に名前をつける
terraform {
required_version = ">= 1.9"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "ap-northeast-1"
}
variable "project" {
type = string
}
variable "environment" {
type = string
}
locals {
# 繰り返し使うプレフィックスを1か所で定義
name_prefix = "${var.project}-${var.environment}"
# 条件式の結果に名前をつける
is_production = var.environment == "prd"
# 条件から派生する値を計算
retention_days = local.is_production ? 90 : 7
multi_az = local.is_production ? true : false
}
resource "aws_cloudwatch_log_group" "app" {
name = "/aws/${local.name_prefix}/app"
retention_in_days = local.retention_days # 毎回条件式を書かなくて済む
tags = {
Name = "${local.name_prefix}-log-group"
Environment = var.environment
ManagedBy = "terraform"
}
}
ケース2: 共通タグのDRY化
locals {
# 全リソースに付けるタグを一元管理
common_tags = {
Project = var.project
Environment = var.environment
ManagedBy = "terraform"
Owner = "infra-team"
}
}
data "aws_ami" "amazon_linux_2023" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-*-x86_64"]
}
}
resource "aws_instance" "web" {
ami = data.aws_ami.amazon_linux_2023.id
instance_type = "t3.micro"
# merge()で共通タグ + 個別タグを合成
tags = merge(local.common_tags, {
Name = "${local.name_prefix}-web"
Role = "web-server"
})
}
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
tags = merge(local.common_tags, {
Name = "${local.name_prefix}-vpc"
})
}
ケース3: for式と組み合わせたデータ変換
variable "subnet_configs" {
type = list(object({
name = string
cidr = string
az = string
}))
default = [
{ name = "public-1a", cidr = "10.0.1.0/24", az = "ap-northeast-1a" },
{ name = "private-1a", cidr = "10.0.11.0/24", az = "ap-northeast-1a" },
]
}
locals {
# listをfor_eachに渡せるmapに変換(for式)
# ← この変換はvariableには書けない(式が書けないため)
subnets_map = { for s in var.subnet_configs : s.name => s }
}
resource "aws_subnet" "main" {
for_each = local.subnets_map # localsを経由してfor_eachに渡す
vpc_id = aws_vpc.main.id
cidr_block = each.value.cidr
availability_zone = each.value.az
tags = merge(local.common_tags, {
Name = each.key
})
}
5. 判断フローチャート
値を定義したい
│
▼
「Terraformの外部(CIやオペレーター)から変えたい?」
│
Yes ─┤ No
│ │
▼ ▼
variable 「コード内で式や計算をしたい?」
(tfvars/-varで渡す) │
Yes ─┤ No
│ │
▼ ▼
locals variable の
(for式・計算) default値で十分
6. よくあるアンチパターン
❌ アンチパターン1: localsで書くべきものをvariableに書く
# ❌ 外から変えない計算結果をvariableに書くのは間違い
variable "name_prefix" {
default = "myapp-dev" # 環境が変わったら手動で変える必要がある
# → 実態はprojectとenvironmentから計算できる派生値
}
# ✅ localsで計算するのが正しい
locals {
name_prefix = "${var.project}-${var.environment}" # 自動で決まる
}
❌ アンチパターン2: variableで書くべきものをlocalsに書く
# ❌ 環境ごとに変えたい値をlocalsに書くと、コードを直接変更しないといけない
locals {
environment = "prd" # コードを書き換えないとdev/stgにできない
}
# ✅ variableにすべき
variable "environment" {
type = string
default = "dev"
}
❌ アンチパターン3: variableに式を書こうとする
# ❌ variableのdefaultには式を書けない(文字列・数値・リスト等の固定値のみ)
variable "name_prefix" {
default = "${var.project}-${var.environment}" # Error!
}
# ✅ localsで計算する
locals {
name_prefix = "${var.project}-${var.environment}"
}
7. variableとlocalsを組み合わせた設計例
実務ではvariableとlocalsを組み合わせて使います。variableで外部入力を受け取り、localsでその値を加工・派生させるパターンが最も一般的です。
# ── 入力(外から変えられる) ──────────────────────
variable "project" {
description = "プロジェクト名"
type = string
}
variable "environment" {
description = "環境名(dev/stg/prd)"
type = string
}
variable "owner_team" {
description = "担当チーム名"
type = string
default = "infra-team"
}
# ── 計算・派生値(コード内で自動的に決まる) ─────────
locals {
# variableから計算する値
name_prefix = "${var.project}-${var.environment}"
is_production = var.environment == "prd"
# 環境に応じて変わる設定(外から渡す必要はない)
instance_type = local.is_production ? "t3.medium" : "t3.micro"
retention_days = local.is_production ? 90 : 7
# タグの共通定義
common_tags = {
Project = var.project
Environment = var.environment
Owner = var.owner_team
ManagedBy = "terraform"
}
}
8. 関連記事
- locals(ローカル値)の使い方 — localsの構文と全ユースケース
- variable(入力変数)の使い方 — variableの構文・型制約・validation
- for式の使い方 — localsと組み合わせるfor式
- output(出力値)の使い方 — variableの「出力側」
- tfvarsファイル — 変数値の管理と読み込み順序
- resourceブロック — 基本構文と使い方
9. まとめ
variableは外部から値を渡すもの。tfvarsやCI環境変数から変えられるlocalsはコード内で計算・整理するもの。外から変えられない代わりに式が書ける- 「外から変えたいか?」→Yes:
variable/ No:「式を書きたいか?」→Yes:locals - アンチパターン:
variableに式は書けない。localsで環境切り替えをしないこと - 実務の定番:
variableで外部入力を受け取り、localsでプレフィックス・タグ・派生値を計算する
動作確認バージョン: Terraform >= 1.9 / AWS Provider ~> 5.0 対象リージョン: ap-northeast-1(東京) 公式ドキュメント(variable): https://developer.hashicorp.com/terraform/language/values/variables 公式ドキュメント(locals): https://developer.hashicorp.com/terraform/language/values/locals