Mastering Terraform Loops with Examples
Terraform supports powerful loops for data transformation, resource creation, and simplifying configurations. Here’s a concise guide with sample inputs and outputs.
Table of Contents
- For Expression Loops
- Count Loops
- For_each Loops
- Dynamic Blocks
- Nested Loops
- Flattening Loops
- Conditional Loops
- Nested Object Processing
- Key Filtering (Map Transformation)
- Tuple Expansion (Zip Lists)
- Reverse Lookup (Key Search)
- Data Grouping (Grouping by Keys)
- Combining Lists with Conditional Filters
- Map Flattening (Nested Map Expansion)
- Filtering and Mapping (Conditional Map Processing)
- Index Looping (Manual Index Tracking)
- Combining Multiple Maps (Merge Maps)
- Counting Specific Values (Data Aggregation)
- Transform List to Map (Zipping)
- List Unpacking (Using Dynamic Values)
- List Expansion with Conditions
- Key-Value Reverse Lookup (Find by Value)
- List Reduction (Combining Data)
- Generating Sequential Values (Custom Index Range)
- Unique Value Extraction (Distinct)
- Filtering with Multiple Conditions
- Map with Custom Keys
- Nested Loops with Conditions
- Flattening Nested Maps
- Conditional Key Assignment
- Nested Maps with Dynamic Keys
- Data Aggregation by Groups
- Data Aggregation with Nested Loops
1. For Expression Loops
Transform lists or maps into new collections.
Example:
variable "nz_national_parks" { default = ["Tongariro", "Fiordland", "Abel Tasman"] } locals { park_messages = [for park in var.nz_national_parks : "${park} National Park is a must-visit in New Zealand."] } output "nz_park_messages" { value = local.park_messages } Output:
[ "Tongariro National Park is a must-visit in New Zealand.", "Fiordland National Park is a must-visit in New Zealand.", "Abel Tasman National Park is a must-visit in New Zealand." ] 2. Count Loops
Create multiple instances of a resource using count.
variable "nz_cities" { default = ["Auckland", "Wellington", "Christchurch"] } locals { city_details = [ for i in range(length(var.nz_cities)) : { index = i name = var.nz_cities[i] } ] } output "created_cities" { value = local.city_details } Output:
[ { "index": 0, "name": "Auckland" }, { "index": 1, "name": "Wellington" }, { "index": 2, "name": "Christchurch" } ] 3. For_each Loops
Create dynamic resources, maps, or sets.
Example:
variable "wellington_places" { default = { "Te Papa Museum" = "Museum of New Zealand" "Mount Victoria" = "Scenic Lookout" "Cuba Street" = "Shopping & Dining Hub" "Wellington Cable Car" = "Historic Transport" } } locals { famous_places = { for place, description in var.wellington_places : place => { name = place description = description } } } output "famous_places_in_wellington" { value = local.famous_places } Output:
{ "Te Papa Museum": { "name": "Te Papa Museum", "description": "Museum of New Zealand" }, "Mount Victoria": { "name": "Mount Victoria", "description": "Scenic Lookout" }, "Cuba Street": { "name": "Cuba Street", "description": "Shopping & Dining Hub" }, "Wellington Cable Car": { "name": "Wellington Cable Car", "description": "Historic Transport" } } 4. Dynamic Blocks
Generate nested blocks inside resources.
Example:
variable "nz_volcanoes" { default = [ "Mount Ruapehu", "Mount Taranaki", "White Island" ] } locals { volcano_locations = { country = "New Zealand" volcanoes = [ for volcano in var.nz_volcanoes : { name = volcano location = "${volcano == "Mount Ruapehu" ? "Tongariro National Park" : volcano == "Mount Taranaki" ? "Egmont National Park" : "Bay of Plenty"}" } ] } } output "nz_volcano_locations" { value = local.volcano_locations } Output:
{ "country": "New Zealand", "volcanoes": [ { "name": "Mount Ruapehu", "location": "Tongariro National Park" }, { "name": "Mount Taranaki", "location": "Egmont National Park" }, { "name": "White Island", "location": "Bay of Plenty" } ] } 5. Nested Loops
Create combinations or nested outputs.
Example:
variable "countries" { default = [ { name = "New Zealand", cities = ["Auckland", "Wellington"] }, { name = "Singapore", cities = ["Singapore City"] }, { name = "Philippines", cities = ["Manila", "Capiz"] } ] } locals { country_city_pairs = [ for country in var.countries : [for city in country.cities : "${country.name}: ${city}"] ] } output "country_city_pairs" { value = local.country_city_pairs } Output:
[ ["New Zealand: Auckland", "New Zealand: Wellington"], ["Singapore: Singapore City"], ["Philippines: Manila", "Philippines: Capiz"] ] 6. Flattening Loops
Merge lists of lists into a single list.
Example:
variable "nz_regions" { default = [ ["Auckland", "Wellington"], ["Christchurch", "Queenstown"], ["Dunedin", "Hamilton"] ] } locals { flattened_regions = flatten(var.nz_regions) } output "flattened_nz_regions" { value = local.flattened_regions } Output:
[ "Auckland", "Wellington", "Christchurch", "Queenstown", "Dunedin", "Hamilton" ] 7. Conditional Loops
Filter data with conditions.
Example:
variable "numbers" { default = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] } locals { even_numbers = [for num in var.numbers : num if num % 2 == 0] } output "even_numbers" { value = local.even_numbers } Output:
[ 2, 4, 6, 8, 10 ] 8. Nested Object Processing
Process nested lists of New Zealand landmarks into structured outputs.
Example:
variable "nz_landmarks" { default = [ { region = "North Island" landmarks = ["Sky Tower", "Te Papa Museum"] }, { region = "South Island" landmarks = ["Milford Sound", "Mount Cook"] } ] } locals { nested_landmarks = [ for landmark_data in var.nz_landmarks : [ for landmark in landmark_data.landmarks : { region = landmark_data.region landmark = landmark } ] ] } output "nested_nz_landmarks" { value = local.nested_landmarks } Output:
[ [ { "region": "North Island", "landmark": "Sky Tower" }, { "region": "North Island", "landmark": "Te Papa Museum" } ], [ { "region": "South Island", "landmark": "Milford Sound" }, { "region": "South Island", "landmark": "Mount Cook" } ] ] 9. Key Filtering (Map Transformation)
Filter maps based on specific keys.
Example:
variable "nz_heritage_sites" { default = { "Waitangi Treaty Grounds" = "Historic" "Tongariro National Park" = "Natural" "Old Government Buildings" = "Architectural" "Milford Sound" = "Natural" } } locals { natural_sites = { for site, type in var.nz_heritage_sites : site => type if type == "Natural" } } output "filtered_heritage_sites" { value = local.natural_sites } Output:
{ "Tongariro National Park": "Natural", "Milford Sound": "Natural" } 10. Tuple Expansion (Zip Lists)
Combine two lists into a structured output.
Example:
variable "nz_fruits" { default = ["Kiwi", "Feijoa", "Tamarillo"] } variable "nz_fruit_colors" { default = ["Green", "Brown", "Red"] } locals { fruit_details = zipmap(var.nz_fruits, var.nz_fruit_colors) } output "fruit_color_map" { value = local.fruit_details } Output:
{ "Kiwi": "Green", "Feijoa": "Brown", "Tamarillo": "Red" } 11. Reverse Lookup (Key Search)
Find a key in a map based on its value.
Example:
variable "nz_wonders" { default = { "Mount Cook" = "Highest Mountain" "Milford Sound" = "Fjord" "Franz Josef Glacier" = "Glacier" } } locals { highest_mountain = tomap(var.nz_wonders) wonder_found = [for key, value in local.highest_mountain : key if value == "Highest Mountain"] } output "nz_highest_mountain" { value = local.wonder_found[0] } Output:
"Mount Cook" 12. Data Grouping (Grouping by Keys)
Group data into categorized lists.
Example:
variable "nz_animals" { default = { "Kakapo" = "Bird" "Kiwi" = "Bird" "Weta" = "Insect" "Tuataras" = "Reptile" "Tuatara" = "Reptile" } } locals { # Correctly group animals by their type animal_groups = { for type in distinct(values(var.nz_animals)) : type => [ for key, value in var.nz_animals : key if value == type ] } } output "grouped_animals" { value = local.animal_groups } Output:
{ "Bird": ["Kakapo", "Kiwi"], "Insect": ["Weta"], "Reptile": ["Tuataras", "Tuatara"] } 13. Combining Lists with Conditional Filters
Conditionally filter and combine two lists into one.
Example:
variable "nz_scenic_spots" { default = ["Mount Cook", "Milford Sound", "Abel Tasman"] } variable "popular_spots" { default = ["Milford Sound", "Sky Tower"] } locals { combined_spots = [ for spot in concat(var.nz_scenic_spots, var.popular_spots) : spot if !contains(var.nz_scenic_spots, spot) || !contains(var.popular_spots, spot) ] } output "unique_spots" { value = local.combined_spots } Output:
[ "Mount Cook", "Abel Tasman", "Sky Tower" ] 14. Map Flattening (Nested Map Expansion)
Expand a nested map into a list of key-value pairs.
Example:
variable "nested_map" { default = { "New Zealand" = { "City" = "Wellington" "Region" = "North Island" } "Australia" = { "City" = "Sydney" "Region" = "New South Wales" } } } locals { flattened_map = [ for country, details in var.nested_map : { country = country city = details["City"] region = details["Region"] } ] } output "flattened_map" { value = local.flattened_map } Output:
flattened_map = [ { "city" = "Sydney" "country" = "Australia" "region" = "New South Wales" }, { "city" = "Wellington" "country" = "New Zealand" "region" = "North Island" }, ] 15. Filtering and Mapping (Conditional Map Processing)
Filter and modify a map's values based on a condition.
Example:
variable "city_populations" { default = { "Auckland" = 1500000 "Wellington" = 500000 "Dunedin" = 100000 "Hamilton" = 200000 } } locals { large_cities = { for city, population in var.city_populations : city => population if population > 400000 } } output "large_cities" { value = local.large_cities } Output:
large_cities = { "Auckland" = 1500000 "Wellington" = 500000 } 16. Index Looping (Manual Index Tracking)
Track list indices without using built-in Terraform functions.
Example:
variable "nz_beaches" { default = ["Piha", "Cathedral Cove", "Hot Water Beach"] } locals { indexed_beaches = [ for idx in range(length(var.nz_beaches)) : { index = idx beach = var.nz_beaches[idx] } ] } output "indexed_beaches" { value = local.indexed_beaches } Output:
indexed_beaches = [ { "beach" = "Piha" "index" = 0 }, { "beach" = "Cathedral Cove" "index" = 1 }, { "beach" = "Hot Water Beach" "index" = 2 }, ] 17. Combining Multiple Maps (Merge Maps)
Merge multiple maps into a single map.
Example:
variable "map_one" { default = { "Auckland" = "North Island" "Wellington" = "North Island" } } variable "map_two" { default = { "Christchurch" = "South Island" "Dunedin" = "South Island" } } locals { merged_maps = merge(var.map_one, var.map_two) } output "merged_maps" { value = local.merged_maps } Output:
merged_maps = { "Auckland" = "North Island" "Christchurch" = "South Island" "Dunedin" = "South Island" "Wellington" = "North Island" } 18. Counting Specific Values (Data Aggregation)
Count specific occurrences within a list.
Example:
variable "nz_islands" { default = ["North Island", "South Island", "North Island", "South Island", "North Island"] } locals { island_counts = { "North Island" = length([for i in var.nz_islands : i if i == "North Island"]) "South Island" = length([for i in var.nz_islands : i if i == "South Island"]) } } output "island_counts" { value = local.island_counts } Output:
island_counts = { "North Island" = 3 "South Island" = 2 } 19. Transform List to Map (Zipping)
Convert two lists into a single map.
Example:
variable "nz_cities" { default = ["Auckland", "Wellington", "Christchurch"] } variable "nz_regions" { default = ["North Island", "North Island", "South Island"] } locals { city_region_map = zipmap(var.nz_cities, var.nz_regions) } output "city_region_map" { value = local.city_region_map } Output:
city_region_map = { "Auckland" = "North Island" "Christchurch" = "South Island" "Wellington" = "North Island" } 20. List Unpacking (Using Dynamic Values)
Unpack values from a list using index references.
Example:
variable "nz_lakes" { default = ["Lake Taupo", "Lake Wanaka", "Lake Tekapo"] } locals { first_lake = var.nz_lakes[0] second_lake = var.nz_lakes[1] third_lake = var.nz_lakes[2] } output "unpacked_lakes" { value = { "First" = local.first_lake "Second" = local.second_lake "Third" = local.third_lake } } Output:
unpacked_lakes = { "First" = "Lake Taupo" "Second" = "Lake Wanaka" "Third" = "Lake Tekapo" } 21. List Expansion with Conditions
Expand lists conditionally.
Example:
variable "nz_hiking_tracks" { default = ["Routeburn", "Milford", "Abel Tasman"] } locals { expanded_tracks = [ for track in var.nz_hiking_tracks : { name = track length = "${track == "Milford" ? "53km" : "Unknown"}" } ] } output "expanded_tracks" { value = local.expanded_tracks } Output:
expanded_tracks = [ { "length" = "Unknown" "name" = "Routeburn" }, { "length" = "53km" "name" = "Milford" }, { "length" = "Unknown" "name" = "Abel Tasman" }, ] 22. Key-Value Reverse Lookup (Find by Value)
Find a key using a map’s value.
Example:
variable "nz_capitals" { default = { "Wellington" = "New Zealand" "Canberra" = "Australia" } } locals { country_lookup = [for city, country in var.nz_capitals : city if country == "New Zealand"] } output "nz_capital" { value = local.country_lookup[0] } Output:
nz_capital = "Wellington" 23. List Reduction (Combining Data)
Find a key using a map’s value.
Example:
variable "nz_mountains" { default = ["Mount Cook", "Mount Ruapehu", "Mount Taranaki"] } locals { mountain_list = join(", ", var.nz_mountains) } output "combined_mountains" { value = local.mountain_list } Output:
combined_mountains = "Mount Cook, Mount Ruapehu, Mount Taranaki" 24. Generating Sequential Values (Custom Index Range)
Create a list of sequential values with a custom range.
Example:
variable "start_index" { default = 5 } variable "end_index" { default = 10 } locals { index_list = [for idx in range(var.start_index, var.end_index) : idx] } output "generated_indices" { value = local.index_list } Output:
generated_indices = [ 5, 6, 7, 8, 9, ] 25. Unique Value Extraction (Distinct)
Remove duplicates from a list.
Example:
variable "nz_fruits" { default = ["Kiwi", "Feijoa", "Kiwi", "Tamarillo", "Feijoa"] } locals { unique_fruits = distinct(var.nz_fruits) } output "distinct_fruits" { value = local.unique_fruits } Output:
distinct_fruits = tolist([ "Kiwi", "Feijoa", "Tamarillo", ]) 26. Filtering with Multiple Conditions
Filter a list based on multiple conditions.
Example:
variable "nz_lakes" { default = ["Lake Taupo", "Lake Tekapo", "Lake Wanaka", "Lake Rotoiti"] } locals { filtered_lakes = [for lake in var.nz_lakes : lake if lake != "Lake Tekapo" && lake != "Lake Rotoiti"] } output "filtered_lakes" { value = local.filtered_lakes } Output:
filtered_lakes = [ "Lake Taupo", "Lake Wanaka", ] 27. Map with Custom Keys
Create a custom map with formatted keys.
Example:
variable "nz_islands" { default = ["North Island", "South Island"] } locals { island_map = { for idx, island in var.nz_islands : "Island_${idx}" => island } } output "formatted_island_map" { value = local.island_map } Output:
formatted_island_map = { "Island_0" = "North Island" "Island_1" = "South Island" } 28. Nested Loops with Conditions
Create nested combinations with a filtering condition.
Example:
variable "countries" { default = ["New Zealand", "Australia"] } variable "cities" { default = ["Auckland", "Sydney", "Wellington"] } locals { country_city_pairs = [ for country in var.countries : [ for city in var.cities : "${country}-${city}" if city != "Sydney" ] ] } output "country_city_combinations" { value = local.country_city_pairs } Output:
country_city_combinations = [ [ "New Zealand-Auckland", "New Zealand-Wellington", ], [ "Australia-Auckland", "Australia-Wellington", ], ] 29. Flattening Nested Maps
Flatten a nested map structure into key-value pairs.
Example:
variable "country_details" { default = { "New Zealand" = { "Capital" = "Wellington" "Largest City" = "Auckland" } "Australia" = { "Capital" = "Canberra" "Largest City" = "Sydney" } } } locals { flat_country_details = [ for country, details in var.country_details : { country = country capital = details["Capital"] largest_city = details["Largest City"] } ] } output "flattened_country_details" { value = local.flat_country_details } Output:
flattened_country_details = [ { "capital" = "Canberra" "country" = "Australia" "largest_city" = "Sydney" }, { "capital" = "Wellington" "country" = "New Zealand" "largest_city" = "Auckland" }, ] 30. Conditional Key Assignment
Assign keys in a map conditionally.
Example:
variable "nz_regions" { default = ["Northland", "Canterbury", "Otago"] } locals { region_assignments = { for region in var.nz_regions : region => "${region == "Canterbury" ? "South Island" : "Other Region"}" } } output "conditional_region_map" { value = local.region_assignments } Output:
conditional_region_map = { "Canterbury" = "South Island" "Northland" = "Other Region" "Otago" = "Other Region" } 31. Nested Maps with Dynamic Keys
Create dynamic keys inside a map.
Example:
variable "city_data" { default = { "Auckland" = "North Island" "Wellington" = "North Island" "Christchurch" = "South Island" } } locals { dynamic_city_map = { for city, island in var.city_data : "City_${city}" => { name = city island = island } } } output "dynamic_city_map" { value = local.dynamic_city_map } Output:
dynamic_city_map = { "City_Auckland" = { "island" = "North Island" "name" = "Auckland" } "City_Christchurch" = { "island" = "South Island" "name" = "Christchurch" } "City_Wellington" = { "island" = "North Island" "name" = "Wellington" } } 32. Data Aggregation by Groups
Group elements into lists based on a common key.
Example:
variable "nz_landmarks" { default = { "Sky Tower" = "Auckland" "Te Papa" = "Wellington" "Milford Sound" = "Fiordland" "Mount Cook" = "Canterbury" } } locals { landmark_groups = { for location in distinct(values(var.nz_landmarks)) : location => [for landmark, place in var.nz_landmarks : landmark if place == location] } } output "grouped_landmarks" { value = local.landmark_groups } Output:
grouped_landmarks = { "Auckland" = [ "Sky Tower", ] "Canterbury" = [ "Mount Cook", ] "Fiordland" = [ "Milford Sound", ] "Wellington" = [ "Te Papa", ] } 33. Data Aggregation with Nested Loops
Aggregate items using nested loops for complex data structures.
Example:
variable "nz_fish_species" { default = { "Trout" = { habitats = [ "Lake Taupo", "Waikato River", ] }, "Snapper" = { habitats = [ "Hauraki Gulf", "Bay of Islands", ] } } } locals { fish_habitats = flatten([ for fish, details in var.nz_fish_species : [ for habitat in details.habitats : { species = fish habitat = habitat } ] ]) } output "grouped_fish_habitats" { value = local.fish_habitats } Output:
grouped_fish_habitats = [ { "habitat" = "Hauraki Gulf" "species" = "Snapper" }, { "habitat" = "Bay of Islands" "species" = "Snapper" }, { "habitat" = "Lake Taupo" "species" = "Trout" }, { "habitat" = "Waikato River" "species" = "Trout" }, ] Conclusion
These examples showcase various Terraform loop patterns, highlighting dynamic map creation, list manipulation, conditional logic, and data aggregation.
Let me know if you'd like additional patterns! 🚀
Top comments (0)