Terraform

Terraform 変数型の型制約と一貫性: string/list/map/object を正しく使い分ける

2026-04-19
NicheeLab編集部

入力変数の型を曖昧にすると、モジュール利用時の誤入力や予期せぬ差分が起きやすくなります。Terraform は HCL2 の型システムを持ち、variable ブロックの type で型制約を宣言できます。この記事では、特に利用頻度の高い string、list、map、object の4型に絞り、型制約と一貫性の観点から設計・実装の勘所を整理します。

試験(Terraform Associate)では、型ごとの性質や挙動、validation、for_each など周辺機能との組み合わせが頻出です。実務の設計原則と一緒に押さえると、得点源にできます。

型制約の基本と4つの主要型

Terraform の入力変数は variable ブロックで宣言し、type 引数で型制約を付けると、plan/apply 時にユーザー入力や tfvars の値が検証されます。default を付けると、その値に合わせて型が暗黙決定されますが、モジュール境界の契約を明確にするため、明示的な type 指定を推奨します。

string は単一値、list は順序を持つ同一型の並び、map はキーと値の辞書(順序なし)、object は属性スキーマを固定した構造体的な型です。object はモジュール API の契約固定に向き、map は任意キーの辞書を受けたい場合に便利です。list は順序重要な入力(例: CIDR の優先順)で使います。

any は柔軟ですが、検証が弱くなり不正入力を見逃しやすいので、移行の過渡期を除き避けるのが安全です。

  • 明示的な type は「利用者と提供者の契約」。将来の破壊的変更を減らす
  • list は順序を保持、map は順序を保証しない(差分の見え方に影響)
  • object は属性の存在と型を固定。入力の厳格性が高い
  • variable.validation で値域チェックを追加し、型だけでは守れない一貫性も担保する
典型的リテラル例主な用途注意点
string"prod"環境名、リージョン、識別子空文字や許容文字の検証を validation で併用
list(string)["web", "api"]順序あるエントリ列(セキュリティルール等)for_each には直接使えない(map/set へ変換が必要)
map(string){ env = "prod", team = "platform" }タグ/ラベル、任意キー辞書順序なし。lookup/merge を多用する設計が定番
object({ name=string, size=string }){ name = "app", size = "t3.small" }モジュール入出力の契約固定全属性が必須(欠落はエラー)。拡張時は後方互換に配慮
list(object({...}))[{ name="a" }, { name="b" }]同型オブジェクトの配列(複数リソース駆動)for_each 用に key 化(name など)して map 化が実務で安定

型制約と検証の評価フロー(入力 → 型チェック → モジュール)

tfvars / -varenvironment varsvariable.type(string/list/...)validation block(値域/形式検証)module inputs(resource args)入力 → variable.type → validation → module inputs

主要4型の宣言例(型制約つき)

variable "env" {
  type        = string
  description = "デプロイ環境(dev/stg/prod)"
  validation {
    condition     = contains(["dev", "stg", "prod"], var.env)
    error_message = "env は dev/stg/prod のいずれかにしてください。"
  }
}

variable "subnets" {
  type        = list(string)
  description = "サブネットIDの順序付きリスト"
}

variable "tags" {
  type        = map(string)
  description = "共通タグ"
  default     = {}
}

variable "server" {
  type = object({
    name = string
    size = string
    tags = map(string)
  })
  description = "単一サーバの仕様"
}

string の実務パターンと落とし穴

string は最も単純ですが、命名規則や許容値の制御を甘くすると、クラウド側の命名制約に引っかかったり、環境の取り違えが起こります。validation で値域や正規表現を併用するのが実務では標準です。

マルチライン文字列が必要ならヒアドキュメント(<<-EOT ... EOT)を使えますが、入力変数で長文を受けるよりは、テンプレートファイルの利用や locals での構築がメンテしやすいです。

  • 環境名やサービス名は正規表現で安全な文字のみ許可
  • クラウドの最大長(例: 63 文字など)に合わせて length チェック
  • sensitive = true は出力抑制のみ。型や値域は validation で別途担保

string 変数の安全な定義例(正規表現+値域)

variable "env" {
  type        = string
  description = "環境名 (dev|stg|prod)"
  validation {
    condition     = can(regex("^(dev|stg|prod)
NicheeLab を読み込み中…
quot;, var.env)) error_message = "env は dev, stg, prod のいずれかにしてください。" } } variable "service_name" { type = string description = "サービス名(小文字英数字とハイフン、1..30 文字)" validation { condition = can(regex("^[a-z0-9-]{1,30}
NicheeLab を読み込み中…
quot;, var.service_name)) error_message = "service_name は小文字英数字とハイフンのみ(最大30文字)。" } }

list の一貫性: list(string) と list(object)

list は順序が意味を持つ並びです。型制約は list(T) の T が全要素に適用されます。list(string) は ID リストなどに適し、list(object) は同一スキーマのエントリ集合を表現できます。

resource の for_each は map か set に限定されるため、list(object) を直接 for_each には使えません。実務では name などの一意キーを用いて、内包表記で map に変換してから for_each するのが安定です。順序が重要で count を使うケースでは、インデックスに依存する破壊的な並べ替えを避ける設計も重要です。

  • 順序が重要: 差し替え時に意図しない置換を避けるためキー化戦略を検討
  • for_each は map/set のみ。list は { for v in var.list : key(v) => v } で map 化
  • list と tuple の違い: tuple は要素ごとに型が異なりうる(Associate では名称理解レベルで十分)

list(object) を map に変換して for_each する例

variable "servers" {
  description = "配備するサーバ群"
  type = list(object({
    name = string
    size = string
    tags = map(string)
  }))
}

locals {
  servers_by_name = { for s in var.servers : s.name => s }
}

# 例: プロバイダ非依存の擬似リソース
resource "example_server" "this" {
  for_each = local.servers_by_name
  name     = each.value.name
  size     = each.value.size
  tags     = each.value.tags
}

map のキー整合性とデフォルト設計

map(string) はタグやラベルの代表格です。順序は保証されないため、plan の表示順は変動し得ます。一貫性を保つには、map の初期値を {} にしておき、merge で共通タグ・上書きタグを合成するパターンが扱いやすいです。

存在しないキー参照には lookup(map, key, default) を使うと安全です。キーの形式(許容文字)を validation で縛ると、クラウド側の制約に先回りできます。

  • default = {} で呼び出し側の省略を許容
  • merge(var.tags, local.common_tags) の順序に注意(後勝ち)
  • キー形式は regex、値の許容集合は contains/alltrue で検証

map(string) の合成と安全な参照

variable "tags" {
  type        = map(string)
  description = "共通タグ(呼び出し元で上書き可能)"
  default     = {}
  validation {
    condition     = alltrue([for k in keys(var.tags) : can(regex("^[-a-z0-9]+
NicheeLab を読み込み中…
quot;, k))]) error_message = "タグのキーは小文字英数字とハイフンのみ許可。" } } locals { base_tags = { "managed-by" = "terraform" } final_tags = merge(local.base_tags, var.tags) } output "team_tag" { value = lookup(local.final_tags, "team", "unknown") }

object の型設計: スキーマ固定と進化のコツ

object は属性名と型を固定できるため、モジュール境界の契約として強力です。全属性の存在が要求され、欠落すると型不一致でエラーになります。将来的に属性を追加する際は、後方互換(既存利用者の tfvars がそのまま通ること)に配慮して、別の変数として分離する、または map(string) で拡張用フックを設ける戦略が有効です。

object 全体の default に null を使うことはできますが、受け側では null を考慮して coalesce や条件分岐でデフォルト補完する必要があります。個々の属性を null 許容にするには、設計段階で null を許可しない方針に寄せ、明確なデフォルトを用意する方が一貫性を保ちやすいです。

  • 厳密な契約が必要なら object、柔軟性が必要なら map で拡張フック
  • 新属性は互換性に配慮して段階的に導入(既存 tfvars を壊さない)
  • validation で属性値の整合を追加チェック(例: name の形式)

object 変数の設計と validation 例

variable "server" {
  description = "サーバ仕様(厳密スキーマ)"
  type = object({
    name = string
    size = string
    tags = map(string)
  })
  validation {
    condition     = can(regex("^[a-z0-9-]+
NicheeLab を読み込み中…
quot;, var.server.name)) && length(var.server.name) <= 30 error_message = "server.name は小文字英数字とハイフン、30文字以内。" } } locals { server_tags = merge({ "managed-by" = "terraform" }, var.server.tags) } # 利用例(出力) output "server_label" { value = "${var.server.name}:${var.server.size}" }

一貫性戦略と Associate 試験対策ポイント

実務では、変数の型を明示し、validation で値域を縛り、list は map 化して for_each、map は merge/lookup で合成・安全参照、object は契約固定に使う、という定石を徹底すると混乱が減ります。型変換関数(toset/tomap/tolist)で入力を正規化するのも有効です。

試験では、list と map の違い(順序、for_each 可否)、object の厳格性、any の注意、validation の役割が問われやすいです。tfvars と -var/-var-file による入力経路、default の影響、plan 時に型エラーが検出される点も押さえておきましょう。

  • 型は必ず明示。any は基本使わない
  • list → for_each の前に map 化(キーは安定・一意)
  • map は default = {}、merge は後勝ちの順序に留意
  • validation で正規表現・包含チェックを活用
  • terraform validate と plan で早期に型・値エラー検出

入力経路と正規化のスニペット(tfvars と型変換)

# terraform.tfvars 例
env     = "stg"
subnets = ["subnet-aaa", "subnet-bbb"]

# CLI からの指定例
# terraform plan -var-file="env/stg.tfvars"

# 型正規化の一例(list → map)
locals {
  items = ["a", "b", "c"]
  items_map = { for v in local.items : v => upper(v) }
}

問題で確認

Associate

問題 1

モジュールは次の入力変数を受け取ります。tags の型制約に適合する tfvars の定義として正しいものはどれですか? variable "tags" { type = map(string) description = "共通タグ" }

  1. A. tags = { env = "prod", team = "platform" }
  2. B. tags = ["env", "prod"]
  3. C. tags = { env = ["prod"] }
  4. D. tags = "env=prod"

正解: A

map(string) はキーが string、値も string の辞書です。A は key:string → value:string の形で適合。B は list、C は値が list、D は単一の string で不適合です。

よくある質問

map と object の使い分けは?

任意キーの辞書を受けたい(タグなど)場合は map(string)。属性名と型を固定して契約を厳密にしたい場合は object。将来の拡張を見込むなら、必須は object、任意拡張は map で受けるハイブリッドも有効です。

list を for_each に使えないのはなぜ?どう回避する?

for_each は map か set を要求します。list は順序と重複を許すため、安定キーを持ちません。回避策は内包表記で map 化することです({ for v in var.list : key(v) => v })。

型不一致エラーが出たときの基本的な対処は?

variable の type と tfvars/デフォルトの実値を見比べ、toset/tomap/tolist などで正規化します。map(string) に list を入れていないか、object の必須属性が欠落していないかを確認し、validation の条件も再点検してください。

この記事で学んだ内容を問題で確認しましょう

16,000問以上の問題で実力チェック

無料で問題を解いてみる
この記事の著者

NicheeLab編集部

データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。


関連記事
Terraform

Terraform HCL 構文の基礎:Block / Attribute / Expression を正しく使い分ける

Terraform Associate で頻出の HCL 構文を、ブロック・属性・式の3視点で整理。実務で迷いがちな書き...

Terraform

Terraform Authoring & Ops Pro: 上位資格の範囲と対策

上位レベルを想定したTerraformの設計・運用ドメインを整理し、実務で通用する対策を提示。モジュール設計、ステート運...

Terraform

Terraform Providers の基本: プラグイン型アーキテクチャを正しく使いこなす

Associate レベルで押さえるべき Provider の基礎、インストール、バージョニング、認証、エイリアス運用を...

Terraform

Terraform Resourceブロック徹底ガイド: 最小単位のリソース定義

Associateレベルで押さえるべきResourceブロックの構造、依存関係、メタ引数、ライフサイクル制御を実務目線で...

Terraform

Terraform Data Source徹底理解:既存リソースの参照で壊さず足す

Terraform Associate向けに、Data Sourceを用いた既存リソース参照の基本、選択基準、評価順序、...

Terraformの記事一覧 (101件)
© 2026 NicheeLab All rights reserved.