Skip to main content
Let’s move on to the next advanced Terraform construct: dynamic blocks. Dynamic blocks let Terraform feel more programmable while staying declarative. They generate repeated nested blocks dynamically from input data, so you avoid copy-pasting identical nested blocks with only small variations. What dynamic blocks do:
  • Dynamically create nested blocks (useful when a resource expects multiple child blocks of the same type, like rules, routes, or settings).
  • Avoid repeating identical nested configuration with only small variations.
The image explains what dynamic blocks do, highlighting their functions to dynamically create nested blocks and avoid repeating identical nested configurations.
Why use dynamic blocks?
  • When a resource contains repeated nested blocks (for example, NSG rules, firewall application rules, or multiple network rules), dynamic blocks keep your code concise and maintainable.
  • They are common across Azure networking and security resources and help reduce duplication and human error.
The image outlines when to use dynamic blocks, listing NSG rules, firewall rules, and any resource with repeated nested blocks.

Simple NSG example

Start by defining a variable for the ports you want to allow:
Then use a dynamic block inside azurerm_network_security_group to generate one nested security_rule block per port. The security_rule iterator gives you .key (index) and .value (the item):
How this works, step by step:
  • for_each = var.ports iterates over the list of ports.
  • For each item, Terraform emits one nested security_rule block.
  • security_rule.value is the current port (e.g., 80, 443, 22).
  • security_rule.key is the iteration index (0, 1, 2…), which we used to create unique priorities like 100, 101, 102 (via 100 + security_rule.key).
  • Other fields (direction, access, protocol) remain constant for each generated block.
Result (conceptual expansion): for three ports, Terraform will create three nested security_rule blocks similar to these:
This eliminates copy-paste and keeps the configuration compact and easy to maintain.
Azure NSG priority values must be unique per security group and are typically in the range 100–4096. When generating priorities programmatically, ensure the computation yields unique values and stays within Azure’s allowed range.

Alternatives and notes

There are two common ways to define NSG rules in Terraform:
  • Use nested security_rule blocks (inside the azurerm_network_security_group) — good when you want grouped rules defined with the resource and simpler configuration grouping.
  • Use the separate azurerm_network_security_rule resource with a for_each — useful if you prefer each rule as its own top-level resource with independent lifecycle and state addressing.
You can define NSG rules either as nested security_rule blocks (using dynamic) or as separate azurerm_network_security_rule resources with for_each. Choose the style that best fits your lifecycle, referencing needs, and state management preferences.
Comparison (quick reference): Example of the separate-resource approach (using for_each):
Both approaches are valid — nested dynamic is often cleaner when rules are tightly coupled to the NSG, while separate resources can offer different lifecycle semantics and easier targeting in state.

Example: VS Code / local iteration demo

The dynamic-block pattern is also useful when iterating to create many top-level resources. Below is a concise example that builds combinations of environment + app and creates resource groups with for_each.
Example plan output (abbreviated):

FQDN / Firewall rules example

The dynamic-block pattern fits other Azure features where repeated nested blocks occur, such as:
  • Azure Firewall application rules (FQDNs)
  • Firewall network rules
  • Any resource with repeated nested block types
Replace the for_each collection and nested block content appropriately — the pattern remains the same: iterate over a collection and produce one nested block per item.

Full working example (provider + variable + RG + NSG + dynamic rules)

A complete HCL example, ready to use:
Summary
  • Use dynamic blocks when nested block structure is constant but the number of blocks varies.
  • Consider separate resources if you need independent lifecycle control.
  • Always ensure generated values (like NSG priorities) comply with Azure constraints.
Further reading and references:

Watch Video