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
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",
]
}
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)