Combining local variables with for_each

I’m trying to use a for_each within locals to iterate files and assemble an object with various properties, and I would reuse this array of objects in various resources. But it seems like Terraform is not letting me.

Here is some rough code:


locals {
  for_each = fileset("${path.module}/functions", "*.js")

  hey = {
    value = each.value
    something_else = /* ... something else with each.value ... */
  }
}

and this is what terraform validate is telling me:

╷
│ Error: each.value cannot be used in this context
│ 
│   on application.tf line 13, in locals:
│   13:     value = each.value
│ 
│ A reference to "each.value" has been used in a context in which it unavailable, such as when the configuration no longer contains the value in its "for_each" expression. Remove this
│ reference to each.value in your configuration to work around this error.
╵

How can I then make a local array of objects based on a for_each that can be reused in different resources?

Hi @amcsi,

The for_each argument is used in resources in order to create multiple instances of that resource, but locals is not a block which can be repeated in that manner, and has no for_each argument.

What you are looking for a for expressions. While you cannot create multiple locals from a single expressions, you can for example create a list of maps assigned to a single local value with the structure in your example like so:

locals {
  hey = [for f in fileset("${path.module}/functions", "*.js") :
    {
      value          = f
      something_else = "additional: ${f}"
    }
  ]
}
1 Like

@jbardin thanks, your example is very helpful!

I was also looking into things by the way, and I think that an alternative thing I could do is create a null_resource like this:

resource "null_resource" "hey" {
  for_each = fileset("${path.module}/functions", "*.js")

  
  value          = each.value
  something_else = "additional: ${each.value}"
}

…and then reference the values from this null_resource in other resources using for_each null_resource.hey on where I can grab “value” and “something_else”.

This works and is a good use of null_resource, right?

I wouldn’t recommend using a null_resource here unless you want to somehow tie this to a managed resource lifecycle.

In the best case your usage works exactly the same as a local value, but you also have the possibility of introducing aspects of the resource lifecycle behavior where none is actually needed. This also has the drawback of null_resource only containing a single triggers attribute, therefor you are limited to whatever that map(string) can hold, where as local values can be of any arbitrary type.

1 Like

But I didn’t mean to use the triggers attribute at all, and instead, just use any custom, arbitrary property I’d create on the fly on the null_resource. I kind of like the idea of being able to use the cleaner for_each syntax over the uglier for syntax.

But I’ll keep in mind that you think using for in locals is the better practice.