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:

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

📥 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

  1. 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
    }
    
  1. Better Debugging and Output Inspection

Flat structures are easier to print (terraform console) and to understand in logs or outputs.

  1. Simplified Conditionals or Filters
    [for r in local.flattened_routes : r if r.next_hop_type == "VirtualAppliance"]
    
  1. Avoids Nested Loops in Resource Blocks

Terraform doesn't allow nested dynamic blocks inside some resource types — flattening sidesteps this.

  1. 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:

…flattening saves time and reduces cognitive load.

Would you like an example comparing two azurerm_route resource definitions, one with and one without flattening?