Table of Contents
Flattening Terraform Nested Structures
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:
- What kind of data you're referring to (e.g. tabular, JSON, text)?
- What kind of transformation you mean (e.g. normalization, parsing, enrichment, reshaping, encoding, etc.)?
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.
π What the Code Does
- It loops over
local.flattened_subnets, which is a list of subnets. - For each
subnet, it loops oversubnet.routes. - For each route, it builds a new object with selected and derived values.
- It uses
flatten([β¦])to collapse the nested list structure into a single flat list of route objects.
π₯ Sample Input (local.flattened_subnets)
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"
}
]
}
]
}
π€ Transformed Output (flattened_routes)
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:
βοΈ Difference Between Flattened vs Non-Flattened Iteration
| 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 |
β Advantages of Flattening
- Direct Mapping to Terraform Resources
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
}
- Better Debugging and Output Inspection
Flat structures are easier to print (terraform console) and to understand in logs or outputs.
- Simplified Conditionals or Filters
[for r in local.flattened_routes : r if r.next_hop_type == "VirtualAppliance"]
- Avoids Nested Loops in Resource Blocks
Terraform doesn't allow nested dynamic blocks inside some resource types β flattening sidesteps this.
- Makes Module Inputs Simpler
You can pass a clean list of flat objects to modules instead of nested structures.
π§ When You *Donβt* Need Flattening
If you're doing everything inside a single local variable or just outputting values, flattening might not be necessary. But as soon as you:
- map to resources,
- perform filtering, or
- reuse the data in multiple placesβ¦
β¦flattening saves time and reduces cognitive load.
Would you like an example comparing two azurerm_route resource definitions, one with and one without flattening?
