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 GCP Enterprise Baseline and the GCP 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.
How BuiltForProd uses it
Layout. Every environments/<group>/<name>/<region or global>/ folder holds one stack file, and the units it lists come from units/. Generated units land in .terragrunt-stack/, which is git-ignored and never edited.
| Repository | Templates and units | A stage file holds |
|---|---|---|
| GCP Enterprise Baseline | 32 unit definitions; stacks/plat-project for each stage project, stacks/includes/project-common.stack.hcl for each core project | The units of each core project; the template for each plat project |
| Web App Blueprint | stacks/webapp-stage, 11 units in shared-infra/ and blueprint-app/ | Only values: GKE zones and limits, Cloud Armor preview, data-store protection, ArgoCD sync and HA |
| Data and ETL Blueprint | stacks/etl-stage, 5 units in shared-infra/ and blueprint-etl/ | Only values: lake location, soft delete, CMEK, discovery, Spark sizing |
Switch files. The Baseline's feature switches live in four files, each switch on one line with its price: environments/core/security/security.hcl, environments/core/network/us-west1/network.hcl, environments/core/identity/identity.hcl and environments/plat/plat.hcl.
Identities in root.hcl. The generated providers impersonate the target project's deployer sa-acme-terraform-deployer in CI, and locally when TG_IMPERSONATE=1 is set; otherwise engineers run with their own credentials. Units marked by an org-scoped.hcl file act on the organization, the folders or several projects, which a per-project deployer cannot reach, so they never impersonate and run in CI as sa-acme-baseline-ci:
is_ci = get_env("CI", "false") == "true"
is_org_scoped = fileexists("${get_terragrunt_dir()}/org-scoped.hcl")
use_chain = !local.is_org_scoped && (local.is_ci || get_env("TG_IMPERSONATE", "0") == "1")
deployer_sa = "sa-${local.namespace}-terraform-deployer@${local.target_project_id}.iam.gserviceaccount.com"
impersonate_sa = local.use_chain ? local.deployer_sa : ""
# The provider.tf line (with its leading newline) that switches the chain on; empty without a chain.
impersonate_attr = local.impersonate_sa == "" ? "" : "\n impersonate_service_account = \"${local.impersonate_sa}\""
Each generated provider.tf also declares one alias per core project (google.root, google.host, google.network, google.dns, google.auto, google.security, google.audit, google.artifacts), each impersonating that project's own deployer. The blueprints generate aliases for the core projects they write into, all impersonating the stage deployer; see service accounts.
Project identities. The organizations unit writes org_projects.hcl with the organization, folder and project IDs and numbers after every apply, through scripts/write-org-projects.py; the file is committed and root.hcl reads it in every clone and in CI, with a deterministic naming fallback. Nothing in root.hcl calls gcloud.
Dependencies. Every dependency carries complete mock outputs, which scripts/check-mock-outputs.py enforces, so a new environment plans end to end before its dependencies exist; an apply always uses real outputs.
Terms you will see
| Term | Meaning |
|---|---|
| Unit | One module with its inputs and its own state. |
| Stack template | A reusable stack such as plat-project or webapp-stage. |
| Generated tree | .terragrunt-stack/, written by stack generate, never edited. |
| Organization-scoped unit | A unit marked by org-scoped.hcl that runs without impersonation. |
| Switch file | One of the four files that hold the Baseline's feature switches. |
Where to read more
- GCP Enterprise Baseline overview for the repository layout.
- Terragrunt units and stacks for the concept.
- OpenTofu for the engine and its providers.