Skip to main content

Terragrunt

Terragrunt is a thin wrapper around OpenTofu that generates the repetitive parts of every configuration, wires units together through their outputs and runs many of them in dependency order. The Azure Enterprise Baseline and the Azure Web App and Data and ETL Blueprints pin Terragrunt 1.1.6 and use its Stacks layout.

What it does​

A unit is one terragrunt.hcl: one module, one state, its inputs. A stack file (terragrunt.stack.hcl) lists units, or other stack templates, with values, and terragrunt stack generate writes the units into a .terragrunt-stack/ folder. A dependency block reads another unit's outputs; mock outputs stand in for them during validate and plan before that unit exists. generate blocks write files such as backend.tf and provider.tf into every unit, and run --all runs a command over a whole tree in dependency order. A feature flag is a typed switch that can be set per run.

How BuiltForProd uses it​

Layout. Every environments/<group>/<name>/<region or global>/ folder holds one terragrunt.stack.hcl, and the units it lists come from units/. Generated units land in .terragrunt-stack/, which is git-ignored and never edited: a change goes into units/, stacks/ or a stack file and is regenerated.

RepositoryTemplatesA stage or subscription file holds
Azure Enterprise Baselinestacks/plat-subscription, with includes/subscription-common and includes/subscription-linkThe units of each core subscription; the template for each plat subscription
Web App Blueprintstacks/webapp-stage, 13 units in shared-infra/ and blueprint-app/Only values: SKUs, node counts, data-store sizes, sync mode
Data and ETL Blueprintstacks/etl-stage, 5 units in shared-infra/ and blueprint-etl/Only values: lake replication, Spark sizing, trigger sizing

root.hcl. Each repository's root file reads common.hcl, region.hcl and account.hcl, builds the names and tags, and generates three files into every unit: backend.tf (the shared state account, a key per unit path), versions.tf (the only provider pins) and provider.tf. The default azurerm provider targets the unit's own subscription; aliases let a unit write into another one:

RepositoryAliases
Azure Enterprise Baselineroot, hub (core-network), dns, auto, security, audit
Web App Blueprintnetwork, dns, auto, artifacts
Data and ETL BlueprintNone: everything it needs from the landing zone comes from the contract vault

The Baseline's root.hcl also holds one map of the hub units' generated paths, so a dependency on, say, the audit workspace is written as include.root.locals.hub.audit_workspace and the folder name lives in one place.

Dependencies. Every dependency carries complete mock outputs for validate and plan, which scripts/check-mock-outputs.py enforces; an apply always uses real outputs. Two Terragrunt feature flags, security_workspace in the subscription baseline and platform_services in kv-publish, can switch a dependency off and default to on.

Running it. CI runs terragrunt run --all --working-dir environments -- plan over the Baseline and one stage folder at a time in the blueprints, and uploads Terragrunt's JSON run report as an artifact. Locally the same commands run from a stack folder. See GitHub Actions for the workflows.

Terms you will see​

TermMeaning
UnitOne module with its inputs and its own state.
Stack fileterragrunt.stack.hcl, the list of units for one folder.
Stack templateA reusable stack such as webapp-stage, filled with a stage's values.
Generated tree.terragrunt-stack/, written by stack generate, never edited.
Provider aliasA second azurerm provider that targets another subscription.
Mock outputsPlaceholder outputs that let a unit plan before its dependency exists.

Where to read more​