merge / concat / flatten — map・listを動的に組み立てる関数

1. 概要

  • merge — 複数のmapをひとつに結合する
  • concat — 複数のlistをひとつに連結する
  • flatten — ネストしたlistを平坦化する
  • それぞれの使いどころと組み合わせパターン

Terraformでデータ構造を動的に組み立てるとき、mergeconcatflattenは欠かせない関数です。for_eachfor式と組み合わせることで、複雑な設定を簡潔に書けます。


2. merge — 複数のmapを結合する

merge(map1, map2, ...)は、複数のmapをひとつにまとめます。後のmapのキーが優先されます(上書き)。

# terraform consoleで確認
> merge({ a = 1, b = 2 }, { b = 3, c = 4 })
{
  "a" = 1
  "b" = 3  # 後のmapで上書きされた
  "c" = 4
}

共通タグ + リソース固有タグのパターン

terraform {
  required_version = ">= 1.9"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

variable "environment" {
  description = "環境名"
  type        = string
  default     = "dev"
}

locals {
  # 全リソース共通のタグ
  common_tags = {
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

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"

  root_block_device {
    volume_size = 20
    volume_type = "gp3"
    encrypted   = true
  }

  # 共通タグ + リソース固有タグを merge
  tags = merge(local.common_tags, {
    Name = "${var.environment}-web"
    Role = "web"
  })
}

resource "aws_instance" "app" {
  ami           = data.aws_ami.amazon_linux_2023.id
  instance_type = "t3.small"

  root_block_device {
    volume_size = 30
    volume_type = "gp3"
    encrypted   = true
  }

  tags = merge(local.common_tags, {
    Name = "${var.environment}-app"
    Role = "app"
  })
}

複数の設定mapをマージする(後勝ち)

locals {
  # デフォルト設定
  defaults = {
    instance_type = "t3.micro"
    volume_size   = 20
    multi_az      = false
  }

  # 環境固有の上書き(本番環境だけ高スペック)
  prd_overrides = {
    instance_type = "t3.medium"
    multi_az      = true
  }

  # 後のmapが優先される(defaultsのinstance_typeはprd_overridesで上書き)
  final_config = var.environment == "prd" ? merge(local.defaults, local.prd_overrides) : local.defaults
}

3. concat — 複数のlistを連結する

concat(list1, list2, ...)は、複数のlistをひとつに連結します。

# terraform consoleで確認
> concat(["a", "b"], ["c", "d"], ["e"])
["a", "b", "c", "d", "e"]

セキュリティグループのルールを動的に組み立てる

locals {
  # 全環境共通のルール
  base_ingress_rules = [
    { port = 443, cidr = "0.0.0.0/0",   description = "HTTPS" },
    { port = 80,  cidr = "0.0.0.0/0",   description = "HTTP" },
  ]

  # 開発環境追加ルール
  dev_ingress_rules = var.environment == "dev" ? [
    { port = 22, cidr = "10.0.0.0/8", description = "SSH from internal" },
  ] : []

  # 最終的なルール一覧
  all_ingress_rules = concat(local.base_ingress_rules, local.dev_ingress_rules)
}

4. flatten — ネストしたlistを平坦化する

flatten(list)は、入れ子になったlistを1次元のlistに展開します。for_eachと組み合わせて使うことが多いです。

# terraform consoleで確認
> flatten(["a", ["b", "c"], ["d", ["e"]]])
["a", "b", "c", "d", "e"]

for + flattenで2次元ループを実現する

Terraformには2重for_eachがないため、flattenで展開してからfor_eachに渡すパターンがよく使われます。

locals {
  environments = ["dev", "stg", "prd"]
  subnets      = ["subnet-a", "subnet-b", "subnet-c"]

  # 2次元をflattenして1次元リストに展開
  env_subnet_pairs = flatten([
    for env in local.environments : [
      for subnet in local.subnets : {
        env    = env
        subnet = subnet
      }
    ]
  ])
}

# { key = value } の形にしてfor_eachに渡す
resource "aws_route_table_association" "this" {
  for_each = {
    for pair in local.env_subnet_pairs :
    "${pair.env}-${pair.subnet}" => pair
  }

  subnet_id      = each.value.subnet
  route_table_id = "rtb-example"
}

5. 組み合わせパターン

merge + concat + flatten を組み合わせる

locals {
  # 環境ごとに異なるCIDRブロックを定義
  vpc_cidrs = {
    dev = ["10.0.0.0/24", "10.0.1.0/24"]
    prd = ["10.1.0.0/24", "10.1.1.0/24", "10.1.2.0/24"]
  }

  # 全環境のCIDRを1つのlistに集める
  all_cidrs = flatten(values(local.vpc_cidrs))
  # → ["10.0.0.0/24", "10.0.1.0/24", "10.1.0.0/24", "10.1.1.0/24", "10.1.2.0/24"]

  # 追加で許可するCIDR
  extra_cidrs = ["192.168.0.0/16"]

  # 全部まとめる
  final_cidrs = concat(local.all_cidrs, local.extra_cidrs)
}

6. 関連記事


7. まとめ

  • merge(map1, map2, ...) — mapを結合。後のmapのキーが優先(上書き)。共通タグ + 固有タグに最適
  • concat(list1, list2, ...) — listを連結。順序を保持する
  • flatten(list) — ネストしたlistを1次元に展開。for + for_eachの2次元ループに必須
  • これら3つはfor式for_eachlocalsと組み合わせることで最大限の効果を発揮する

動作確認バージョン: Terraform >= 1.9 / AWS Provider ~> 5.0 公式ドキュメント: https://developer.hashicorp.com/terraform/language/functions/merge