===== 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 over ''subnet.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?