Skip to content

The live tree

Everything deployable lives under live/. This page explains how the tree is organised, what counts as a unit, and how the engine and Terragrunt find things in it.

Folder names are management group IDs

Inside live/, the folder tree mirrors the Cloud Adoption Framework management group hierarchy, and each folder is named after the management group ID it represents.

live/                      # the alz root management group
├── platform/              # MG: platform
│   ├── connectivity/      # MG: connectivity
│   ├── identity/          # MG: identity
│   ├── management/        # MG: management
│   └── security/          # MG: security
├── landingzones/          # MG: landingzones
│   ├── corp/              # MG: corp
│   ├── online/            # MG: online
│   └── local/             # MG: local (Azure Local, rarely used)
├── sandbox/               # MG: sandbox
└── decommissioned/        # MG: decommissioned

Every one of those names matches an entry in the architecture definition in the vendored policy library. The alz root itself has no folder of its own. live/ is that level.

_foundation/ is the deliberate exception. It is not a management group. The underscore sorts it to the top of the tree and marks it as special, because the foundation is tenant-global rather than belonging to any single management group.

The four levels

Below a management group folder, the tree narrows scope in a fixed order.

Level Named after Holds
Management group The MG ID. Child MG folders, or a subscription.
Subscription The subscription's purpose, for example corp-workload. subscription.hcl, then region folders.
Region The Azure region, for example westeurope. region.hcl, then units. Use _global for region-agnostic work.
Unit What it deploys, for example network. terragrunt.hcl and main.tf.

A platform management group with exactly one subscription flattens the subscription level away and puts subscription.hcl directly in the management group folder. _foundation/ flattens further still: it carries both subscription.hcl and region.hcl at its own root, with units directly under it.

A worked path, from a real deployment:

live/landingzones/corp/corp-workload/westeurope/network/
     └─ MG ──┘└ MG ┘└ subscription ┘└ region ─┘└ unit ┘

What a unit is

A unit is a leaf folder containing a terragrunt.hcl. That is the whole definition. It pairs two files:

  • terragrunt.hcl includes the root contract, generates the backend, the providers, and the context, pins the subscription, and declares ordering dependencies. It carries no resources.
  • main.tf is plain Terraform. It sources an Azure Verified Module at a pinned version and sets its inputs.

The template ships exactly three units, all under live/_foundation/. Everything else in the tree is a README-only placeholder. A folder with no terragrunt.hcl is not a unit, so discovery walks straight past it and it costs nothing at plan time.

Resource names inside units follow <abbreviation>-<purpose>-<location_short>, for example rg-management-weu and uami-amba-weu.

The scope files

Three files carry scope rather than resources. They set the context a unit inherits.

File Sets Sits at
tenant.hcl Tenant ID and the management group the hierarchy is built under. live/ root, once.
subscription.hcl The subscription a subtree deploys into. Each subscription scope.
region.hcl The region and environment for a subtree. Each region scope.

Units never include these directly. They include root.hcl, which walks up the tree to find them. The nearest ancestor wins, so a connectivity unit picks up a different subscription from the foundation with no per-unit wiring. See The root contract.

How things are found

Three separate mechanisms, and it helps to keep them apart.

Configuration inheritance walks upward. find_in_parent_folders from the unit locates root.hcl, and root.hcl in turn locates tenant.hcl, subscription.hcl, and region.hcl. Nothing is registered anywhere. Position in the tree is the wiring. The values it finds are written into each unit as a generated context.tf, so main.tf reads them as plain Terraform.

State keys derive from position. root.hcl sets the backend key to ${path_relative_to_include()}/terraform.tfstate, so a unit's path under live/ is its state key. Each unit gets its own state file.

Engine discovery is driven by projects.yml at the repository root, which sets root: live as the scan root and include_dependents: true so a change to a unit also re-plans anything downstream of it. See Workflows and discovery config.

Moving a folder moves its state

Because the state key is the path, renaming or moving a unit points it at a new, empty state file. Terraform will plan to create everything the unit already manages. Move the state blob first, or expect a plan that destroys and recreates. The runbook has the safe procedure.

Ordering

Ordering is declared, never inferred. A unit's terragrunt.hcl names the units that must apply before it in a dependencies block. That block sets order only and reads no values.

Across the tree the order is _foundation/ first, because management groups must exist before anything can be placed in them, then platform/ for the connectivity hubs, then landingzones/. Within the foundation the order is management-resources, then landing-zones, then amba.

Next: The root contract.