See it as a diagram
Everything below, as a diagram you can edit. Describe yours and see it in seconds.
No account needed · Editable canvas, not a picture
Three layouts, one question
Environments are expressed in Terraform in three common ways. A directory per environment, each with its own backend and its own state. A single configuration with a tfvars file per environment. Or workspaces, where the same configuration is applied under different state keys selected at apply time.
The layout changes where the values live, not what a reader wants to know, which is always the same question: what is actually different between prod and the others. In practice the answer is small. The same modules, the same wiring, and a short list of divergences: instance sizes and SKUs, replica and node counts, a backup or DR resource that only exists in production, and sometimes a network peering that only exists in dev.
Draw the shape once, annotate the divergences
Datadef parses tfvars files per environment and reads the environment names out of the paths, so they are a property of the model rather than a label someone typed. The rule is one path segment: env, envs, environment, or environments, followed by the name, upper-cased. envs/dev/terraform.tfvars gives DEV, platform/environments/prod/main.tfvars gives PROD, and nothing has to be configured. When a resource or a module is instantiated per environment it stays one node and carries the real numbers, 10 catalogs in DEV and 1 in PROD, instead of appearing ten times or hiding behind a generic times-N.
Multiplicity comes from the source. A for_each over a literal map is counted by its top-level entries. A count expression like var.enable_dr ? 1 : 0 has its flag resolved per environment and prints not deployed (count 0) where it is false. A for_each over a comprehension is not evaluated, so the node says per projects rather than inventing a number, and a module instantiated that way stays one zone with its multiplicity written on it.
One rule keeps the annotations trustworthy. Where an attribute resolves to different literals in different environments and nothing decides which the node should carry, nothing is written: a single-environment value printed on a shared node would read as fact. Counts are the exception, because they can be attributed, which is why a count appears as DEV 10, QUAL 4, PROD 1 while a disputed SKU appears not at all.
What you get is a single canvas where the shared architecture reads normally and the divergences are visible as annotations on the specific nodes that diverge. That is the diagram people actually needed, and it is regenerated on every sync rather than re-drawn per release.
envs/ dev.tfvars catalog_count = 10 sku = "Standard" qual.tfvars catalog_count = 4 sku = "Standard" prod.tfvars catalog_count = 1 sku = "Premium" geo_backup = true parsed result on the canvas: Unity Catalog metastore catalogs: DEV 10, QUAL 4, PROD 1 Storage account SKU: Standard (DEV, QUAL) / Premium (PROD) Geo backup vault PROD only
When environments deserve their own diagram
Split when the topology genuinely diverges rather than when the values do. A production environment in two regions with failover, a dev environment that skips the private networking entirely, or a legacy environment mid-migration: those are different architectures wearing the same repository, and annotations stop helping once roughly a fifth of the nodes differ.
Split also when the audiences differ. A production diagram shown to auditors and a dev diagram used by engineers can legitimately be two artifacts with two levels of detail. Connecting the same repository twice, once per branch or tag, gives each its own synced project.
Do not split just because there are three environments. Three copies of the same picture create a maintenance problem and a trust problem at once, since the moment two of them disagree nobody knows which one was updated last.
FAQ
Should each environment get its own architecture diagram?
How does a diagram know which environment a value belongs to?
What if we use Terraform workspaces instead of directories?
How do we show a resource that exists only in production?
Does annotating environments make the diagram harder to read?