User: give me a sample of data how this is transforming it.
Assistant: Sure — but I’ll need more context to help you properly. Could you clarify:
User: flattened_routes = flatten([
for subnet in local.flattened_subnets : [
for route in subnet.routes : {
subnet_key = subnet.key
route_name = route.name
address_prefix = route.address_prefix
next_hop_type = route.next_hop_type
next_hop_in_ip = try(route.next_hop_in_ip_address, null)
resource_group_name = subnet.virtual_network_resource_group_name
route_table_name = "${subnet.subnet_name}-rt"
}
]
])
Assistant: Great — this is a Terraform expression (in HCL2) using list comprehensions to flatten nested route definitions from subnets. Let’s walk through what it does, and then I’ll give you a sample input and the transformed (flattened) output.
local.flattened_subnets, which is a list of subnets.subnet, it loops over subnet.routes.flatten([…]) to collapse the nested list structure into a single flat list of route objects.locals {
flattened_subnets = [
{
key = "subnet-1"
subnet_name = "app-subnet"
virtual_network_resource_group_name = "rg-network"
routes = [
{
name = "route-to-internet"
address_prefix = "0.0.0.0/0"
next_hop_type = "Internet"
},
{
name = "route-to-vpn"
address_prefix = "10.1.0.0/16"
next_hop_type = "VirtualAppliance"
next_hop_in_ip_address = "10.0.0.4"
}
]
}
]
}
flattened_routes = [
{
subnet_key = "subnet-1"
route_name = "route-to-internet"
address_prefix = "0.0.0.0/0"
next_hop_type = "Internet"
next_hop_in_ip = null
resource_group_name = "rg-network"
route_table_name = "app-subnet-rt"
},
{
subnet_key = "subnet-1"
route_name = "route-to-vpn"
address_prefix = "10.1.0.0/16"
next_hop_type = "VirtualAppliance"
next_hop_in_ip = "10.0.0.4"
resource_group_name = "rg-network"
route_table_name = "app-subnet-rt"
}
]
Would you like help writing this to a .tf output file or passing this to a module/resource?
User: and what is the difference when iterating, what advantages it gives as compared to the one not flattened?
Assistant: Great question — using a flattened structure when iterating over nested data (like subnets → routes) in Terraform offers several practical advantages. Let's break it down:
| Aspect | Without Flattening | With Flattening (your code) |
|---|---|---|
| Structure | Nested iteration: you must loop over subnets, then routes within each subnet | Single-level list of route objects |
| Complexity | More complex — often requires nested for expressions or dynamic blocks inside blocks | Much simpler to iterate with a for_each directly |
| Use in resources/modules | Difficult to map 1:1 with Terraform resources (resource or module) | Can directly use for_each = { for idx, r in local.routes : … } |
| Reusability | Harder to reuse or manipulate individual routes | Easy to filter/map specific routes across subnets |
| Error-prone | Higher risk of misalignment in index or wrong nesting | Cleaner, flatter structure avoids nested tracking |
resource "azurerm_route" "this" {
for_each = { for idx, route in local.flattened_routes : "${route.route_table_name}-${route.route_name}" => route }
name = each.value.route_name
resource_group_name = each.value.resource_group_name
route_table_name = each.value.route_table_name
address_prefix = each.value.address_prefix
next_hop_type = each.value.next_hop_type
next_hop_in_ip_address = each.value.next_hop_in_ip
}
Flat structures are easier to print (terraform console) and to understand in logs or outputs.
[for r in local.flattened_routes : r if r.next_hop_type == "VirtualAppliance"]
Terraform doesn't allow nested dynamic blocks inside some resource types — flattening sidesteps this.
You can pass a clean list of flat objects to modules instead of nested structures.
If you're doing everything inside a single local variable or just outputting values, flattening might not be necessary. But as soon as you:
…flattening saves time and reduces cognitive load.
Would you like an example comparing two azurerm_route resource definitions, one with and one without flattening?