for-each Meta Arguments in Terraform offer a cleaner, more predictable way to loop over complex resources. If you’ve been using the count
meta argument but faced unexpected behavior during updates, switching to for_each
might just be the solution you’re looking for.
In this post, we’ll explore what for_each
does, how it differs from count
, and how to use it properly for dynamic resource creation in Terraform.
Table of Contents
Understanding the Need for for-each
The Problem with Count
Using count
allows you to create multiple resources based on an integer value. However, it introduces limitations when you need to manage resources based on specific identifiers like filenames or server names.
When a list changes—for example, removing the first item—Terraform treats it as an index shift, destroying and recreating resources unnecessarily. This is not ideal in a production environment.
Enter for-each Meta Arguments
The for-each
meta argument solves this problem by looping through maps or sets instead of lists. Rather than tracking resources by numerical index, for_each
uses keys, which makes your infrastructure configuration more stable and readable.
Using for-each with Sets and Maps
Basic Syntax
Here’s a simplified structure:
resource "local_file" "pet" {
for_each = toset(var.filenames)
filename = each.value
content = "Generated by Terraform"
}
In this configuration:
for_each
loops over a set.each.value
represents the current item in the loop.
This setup creates multiple files with unique names from the set.
Converting Lists to Sets for for-each
Why Lists Don’t Work Directly
Terraform does not allow for_each
to loop over lists. If you try, it will throw a configuration error.
Solution 1: Define Variable as Set
You can directly define the variable like this:
variable "filenames" {
type = set(string)
default = ["/root/pets.txt", "/root/dogs.txt", "/root/cats.txt"]
}
This method works well when you’re sure there won’t be duplicates in your data.
Solution 2: Use the toset()
Function
If you prefer using lists or your values are dynamic, convert them to a set using Terraform’s built-in toset()
function:
for_each = toset(var.filenames)
This keeps your input flexible while making it compatible with for_each
.
Why for-each is Better than Count
More Stable Resource Handling
When you delete an element using count
, all following items shift their index. Terraform ends up recreating resources that haven’t actually changed.
With for_each
, only the specific resource linked to the removed key is destroyed, while others remain untouched.
Example
Suppose your filenames set contains:
/root/pets.txt
/root/dogs.txt
/root/cats.txt
If you remove /root/pets.txt
and reapply, only that one file is deleted. The rest stay exactly as they were.
Output Comparison: Count vs for-each
To see the difference, you can add an output block:
output "pet_files" {
value = local_file.pet
}
Output with Count
pet[0]
pet[1]
pet[2]
Output with for-each
pet["/root/dogs.txt"]
pet["/root/cats.txt"]
This distinction shows that with for_each
, resources are managed as a map. Each item is associated with a unique key, making the structure more resilient to changes.
When to Use for-each in Terraform
Use for_each
when:
- You want to create resources with unique identifiers.
- You need predictable and stable resource mapping.
- You’re dealing with sets or maps.
- You want to avoid the drawbacks of index-based updates.
Use count
when:
- You only need a specific number of identical resources.
- Indexing is acceptable or useful.
Conclusion
for-each Meta Arguments in Terraform provide a smarter and more controlled way to loop through resources. By avoiding index-based resource management, you eliminate the risk of unnecessary resource replacement, especially when items are added or removed.
This method is not only more readable but also more maintainable and production-safe. Whether you’re building files, VMs, or cloud resources, for_each
is an essential tool in every Terraform developer’s toolkit.
Frequently Asked Questions (FAQs)
1. What is the difference between count and for-each in Terraform?
count
creates resources based on a numeric index, while for_each
uses unique keys from a map or set, allowing more control.
2. Can I use for-each with a list?
No. Terraform does not allow for_each
with lists directly. Convert the list to a set using the toset()
function.
3. What types of collections work with for-each?
Terraform supports maps and sets with for_each
. These ensure each resource is uniquely identified.
4. Why use for-each over count?
for_each
avoids the issues of resource index shifting that occur with count
, making updates safer and more predictable.
5. How do I prevent resource recreation using for-each?
Because for_each
maps resources by key, only the specific key being changed is affected. Others remain untouched, minimizing disruption.