https://samnot.es/p/nested-loops-in-terraform/

When I first wanted to do nested looping in terraform, a lot of information online said it wasn’t possible. I learned eventually that it is possible, with one caveat, and this is the post I wish I’d found back then. Typical looping syntax in terraform Imagine we’ve got a map of items: locals { items = { "value1": {...}, "value2": {...}, ... "valueN": {...}, } } The way you loop over these items in a flat fashion is like this with a for_each expression

Sam

# How to do nested loops in Terraform?

When I first wanted to do nested looping in terraform, a lot of information online said it wasn’t possible. I learned eventually that it is possible, with one caveat, and this is the post I wish I’d found back then.

Typical looping syntax in terraform

Imagine we’ve got a map of items:

locals {
	items = {
		"value1": {...},
		"value2": {...},
		...
		"valueN": {...},
	}
}

The way you loop over these items in a flat fashion is like this with a for_each expression

for_each = local.items

## each.key is `valueX`
## each.value is the object at that key

I’ll use the example of DataDog dashboard widgets throughout, to keep the demos consistent. With this loop, we could define some graph templates and generate them with a for_each.

resource "datadog_dashboard" "new_dash" {
	for_each = local.items
	widget {
	  ...
	  query = each.value.query
	  ...
	}
}

No nesting

The standard for_each approach does not support nesting though.

Imagine this use case: for a list of services, I want to generate a set of graphs monitoring specific kinds of error produced by that service, grouped by their service.

If I were writing that in Go it would look like:

for _, service := range service {
  serviceGroup := datadog.NewGroup()

  for _, graph := range service.graphs {
    serviceGroup.Add(graph)
  }
}

But the same syntax doesn’t work in Terraform. A second for_each statement won’t work that way.

NB: IF YOU’RE JUST SCANNING THIS POST, THE FOLLOWING APPROACH DOES NOT WORK. KEEP READING.

locals {
  services = {
     service1": {
       "serviceName": "...",
       "errorNames": [....]
     },
     "service2": {
       "serviceName": "...",
       "errorNames": [....]
     },
   }
}

resource "datadog_dashboard" "new_dash" {
  for_each = local.services
  widget {

    # a group of graphs under a heading
    group_definition {
      title = "each.value.serviceName"

      #
      # it will break here
      #
      for_each = each.value.errorNames
      widget {...}
    }
  }
}

You’d imagine we could just nest for_each statements like this, but we can’t.

Flattening option

One option is to use the flatten(...) method, to essentially un-nest the values and create a flat list with one element per thing you want to create.

This would work fine if you don’t care about grouping the results, but in our case and in many use cases, the nesting represents a relationship between the sub-elements which you want to retain.

Nesting with “dynamic” blocks

The solution is to use dynamic blocks. These let you generate one block per iterated value, and crucially allows you to nest these iterators.

Here’s how it works with the same example:

locals {
  services = {
     service1": {
       "serviceName": "...",
       "errorNames": [....]
     },
     "service2": {
       "serviceName": "...",
       "errorNames": [....]
     },
   }
}


resource "datadog_dashboard" "new_dash" {
	
  # add dynamic in front of the block to repeat
  # this gives us one widget per service
  dynamic "widget" {

    # loop over services
    for_each = local.services

    # and name the iterator variable
    iterator = service

    # content keyword separates the iteration syntax and content
    content {
      group_definition {
        title = "each.value.serviceName"

        # another dynamic
        # one widget per error_name
        dynamic "widget" {
          # refer to the iterator variable "service"
          # and loop over its errors
          for_each = service.value.errorNames
          iterator = "error_name"

          content {...}
        }
      }
    }
  }
}

That’s how we do nested looping in Terraform. A few things to note:

  • The dynamic keyword is key. That’s the block which will repeat, for each iterator value inside it.
  • The content keyword separates the loop syntax from what goes inside the repeating block. Make sure you put everything inside a content block for dynamic widgets.
  • The iterator value allows you to name the variable which holds the item. Do NOT put quotes around your iterator variable name, e.g. iterator = "service", which I found will serve cryptic errors.

Caveat: Only blocks can repeat

Because this is a dynamic block feature, we can only iterate on blocks. You can’t place loops wherever you wish. They have to go inside the dynamic block.

You can’t loop over services, then over errorNames without them each corresponding to a block. If you want to do that though, flattening is probably fine for your use case.

ARCHIVE

15 Apr 2026 A Little Humanity 13 Apr 2026 Hamlet - William Shakespeare 13 Apr 2026 The Rise and Fall of the Third Reich - William L. Shirer 13 Apr 2026 The Secret History - Donna Tartt 11 Apr 2026 A Year of Living Simply - Kate Humble 08 Apr 2026 40 Before 40 08 Apr 2026 Montaigne - Stefan Zweig 04 Apr 2026 William Shakespeare: A Very Short Introduction - Stanley Wells 19 Mar 2026 Unreasonable Hospitality - Will Guidara 15 Mar 2026 Hitler's Secret - Rory Clements 15 Mar 2026 Nemesis - Rory Clements 08 Mar 2026 HRV & Me: Taming a messy stressy mind 02 Mar 2026 Nucleus - Rory Clements 19 Feb 2026 Corpus - Rory Clements 08 Feb 2026 Resonance 16 Jan 2026 A Night to Remember: Sinking of the Titanic - Walter Lord 01 Jan 2026 Everything I've read in 2026 (so far) 15 Dec 2025 Someone from the Past (British Library Crime Classics) - Margot Bennett 01 Dec 2025 Death in Ambush (British Library Crime Classics) - Susan Gilruth 23 Nov 2025 A Cold Wind From Moscow - Rory Clements 10 Nov 2025 The Boleyn Traitor - Philippa Gregory 24 Oct 2025 Death Makes a Prophet (British Library Crime Classics) - John Bude 13 Oct 2025 The Cheltenham Square Murder (British Library Crime Classics) - John Bude 04 Oct 2025 Sussex Downs Murders (British Library Crime Classics) - John Bude 22 Sep 2025 The Lake District Murder (British Library Crime Classics) - John Bude 15 Sep 2025 The Mayor of Casterbridge - Thomas Hardy 10 Sep 2025 The Murder of Roger Ackroyd - Agatha Christie 30 Aug 2025 Marble Hall Murders - Anthony Horowitz 25 Jul 2025 Where Angels Fear to Tread -- EM Forster 10 Jul 2025 Steve Jobs -- Walter Isaacson 10 Jul 2025 The Fifth Risk -- Michael Lewis 10 Jul 2025 The Ride of a Lifetime -- Bob Iger 03 Jul 2025 James -- Percival Everett 01 Jul 2025 Great Expectations -- Charles Dickens 23 Jun 2025 Hillbilly Elegy -- JD Vance 10 Jun 2025 Principles 09 Jun 2025 Revenge of the Tipping Point -- Malcolm Gladwell 06 Jun 2025 The Grand Babylon Hotel -- Arnold Bennett 04 Jun 2025 The Seven Husbands of Evelyn Hugo -- Taylor Jenkins Reid 03 Jun 2025 Rebecca -- Daphne du Maurier 29 May 2025 A Promised Land - Barack Obama 29 May 2025 Less - Andrew Sean Greer 13 May 2025 Careless People - Sarah Wynn-Williams 07 May 2025 Looking Glass War - John Le Carre 04 May 2025 A Murder of Quality - John Le Carre 01 May 2025 London Marathon 2025: Training Retrospective 29 Apr 2025 The Human Factor - Graham Greene 28 Apr 2025 London Marathon 2025: Race Review 27 Apr 2025 Photos: London Marathon 2025 27 Apr 2025 Spectating the London Marathon 2025 [Sunday 27th April] 26 Apr 2025 London Marathon 2025: Week 16 23 Apr 2025 Call for the Dead - John Le Carre 21 Apr 2025 London Marathon 2025: Week 15 16 Apr 2025 The Manchurian Candidate - Richard Condon 13 Apr 2025 London Marathon 2025: Week 14 05 Apr 2025 London Marathon 2025: Week 13 30 Mar 2025 London Marathon 2025: Week 12 26 Mar 2025 Effortless - Greg Mckeown 23 Mar 2025 London Marathon 2025: Week 11 16 Mar 2025 London Marathon 2025: Week 10 09 Mar 2025 London Marathon 2025: Week 9 02 Mar 2025 London Marathon 2025: Week 8 22 Feb 2025 London Marathon 2025: Week 7 16 Feb 2025 London Marathon 2025: Week 6 16 Feb 2025 Problems & [Meta] Problem Solving 14 Feb 2025 Little Dribbling - Bill Bryson 10 Feb 2025 Bring Up the Bodies - Hilary Mantel 09 Feb 2025 London Marathon 2025: Week 5 09 Feb 2025 Three Zero 03 Feb 2025 The iPad mini has genuinely changed my life [no hyperbole] 02 Feb 2025 London Marathon 2025: Week 4 28 Jan 2025 Coming AI: Valuing Humans in a world where they have no economic value 28 Jan 2025 Value & Price 27 Jan 2025 The Vegetarian - Han Kang 27 Jan 2025 Wolf Hall - Hilary Mantel 26 Jan 2025 London Marathon 2025: Week 3 19 Jan 2025 Deriving my own proof for Unitary matrices 19 Jan 2025 London Marathon 2025: Week 2 17 Jan 2025 David Copperfield - Charles Dickens 12 Jan 2025 London Marathon 2025: Week 1 09 Jan 2025 NYC & DC '24 08 Jan 2025 Linear Algebra Playground 07 Jan 2025 Configuring an IKEA wireless light switch: Saving you the pain 07 Jan 2025 Goals & Goal-setting 06 Jan 2025 Digital Feeds 05 Jan 2025 London Marathon 2025: Training Begins 01 Jan 2025 Everything I've read in 2025