For_each to make multiple types of a resource

I want to use a variable to control making multiple resources of a different type. For instance, multiple AWS EC2’s or RDS instances. Here’s my test:

locals {
  instances = {
    "t2.large"  = 3
    "t2.medium" = 2
  }
}

output "out" {
  value = [for type, count in local.instances : { for num in range(count) : "${type}_${num}" => type }]
}

This yields:

out = [
  {
    "t2.large_0" = "t2.large"
    "t2.large_1" = "t2.large"
    "t2.large_2" = "t2.large"
  },
  {
    "t2.medium_0" = "t2.medium"
    "t2.medium_1" = "t2.medium"
  },
]

I want to be able to use something like this feeding a for_each for an aws_instance resource but I’m not sure how to have that be a single map/hash for it to work.

Hi @grimm26,

The pattern for this sort of thing is to first construct a set or list of objects describing the objects you want to create, often using flatten, and then to project that to a map to use with for_each.

For example:

locals {
  instance_type_counts = {
    "t2.large"  = 3
    "t2.medium" = 2
  }
  instances = flatten([
    for type, count in local.instance_type_counts : [
      for i in range(count) : {
        instance_type = type
        index         = i
      }
    ]
  ])
}

resource "aws_instance" "example" {
  for_each = {
    for inst in local.instances : "${inst.instance_type}:${inst.index}"
  }

  instance_type = each.value.instance_type
  # ...
}

For this sort of situation where there is no single “obvious” key for a given object (because it’s constructed from several values) I usually prefer to do the final projection to a map inline in the for_each expression; that way the definition of the instance keys is stated directly within the resource block so that future maintainers can find it more easily than if it where defined somewhere else. Functionally though there is no reason you couldn’t do that part in a local value too, or in an output as you had in your original example.

This will result in instances with addresses like aws_instance.example["t2.large:1"], so it’s important to note that reducing the count for a particular instance type will always cause the instances with the highest indices to be planned for destruction because those are the keys that will vanish from the derived map. If all of your instances are considered equivalent and thus it doesn’t matter which ones get destroyed then that might well be fine, but I just wanted to be explicit about that caveat! :smiley: