TerraformXV · Environment Architecture and State BoundariesProduction Terraform
Why Multiple Environments
What you'll learn
- Explain why a single production environment is operationally unsound
- Identify the boundary between production and non-production
- Describe the role of dev, staging, and production environments
- Recognise when an environment is over-engineered
Prerequisites
None — start here.
Verified against Terraform CLI 1.9.x · OpenTofu 1.7.x · HCL 2.0 · bpg/proxmox provider 0.66+ · hashicorp/local provider 2.5+ · hashicorp/null provider 3.2+ · hashicorp/random provider 3.6+ · hashicorp/http provider 3.4+ · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · 2026-08-13
A production Terraform estate that runs a single environment is a production Terraform estate that learns from outages. The lesson teaches why real teams operate at least two environments, what each one is for, and where the production boundary lives.
The single-environment trap
Consider a team that operates a single AWS account and calls it “production”. The team writes Terraform, applies changes, and the changes go live. There is no staging. There is no dev. The state file is the production state.
The first sign of trouble is a routine schema migration. The team wants to add a column to a critical table. The migration is applied to production. The application breaks. The team rolls back. They never know whether the migration is correct because they had nowhere to try it first.
The second sign of trouble is a refactor. The team wants to rename a security group. The refactor is applied to production. The application breaks. The team realises that the security group is referenced by ten other resources that they forgot about.
A single-environment estate is a test-in-production estate. The production boundary is the boundary between “things we have tested” and “things we have not tested”. When there is only one environment, the boundary is the customer.
What the environments are for
A production estate typically runs three environments, each with a distinct purpose:
dev. A disposable environment where engineers experiment. Drift is expected. Resources are torn down at the end of the week. The cost of an outage is the time of one engineer. The state is not load-bearing.
staging. A long-lived environment that mirrors production in shape but not in load. The same Terraform modules, the same provider configuration, different inputs. The cost of an outage is the time of a few engineers. The state is load-bearing for the staging estate.
production. The customer-facing environment. Drift is a paging incident. Resources are replaced, not modified. The cost of an outage is revenue, reputation, and the on-call rotation. The state is load-bearing for the entire company.
The boundaries between these environments are operational boundaries, not naming conventions. The dev environment does not have production data. The staging environment does not have production traffic. The production environment does not have engineer SSH keys.
The promotion flow
A change moves through the environments in order:
dev → staging → production
(safe) (cautious) (controlled)
The change is a Terraform plan. The plan is applied to dev. The plan is reviewed. The plan is applied to staging. The plan is reviewed. The plan is applied to production. The plan is reviewed.
The promotion is not a copy of the apply. The promotion is the
same configuration with different inputs (-var-file). The
main.tf is shared across environments; the prod.tfvars is
not.
# Apply to dev
terraform apply -var-file=dev.tfvars
# Apply to staging
terraform apply -var-file=staging.tfvars
# Apply to production
terraform apply -var-file=prod.tfvars
The plan output differs between environments because the inputs differ. The same module, the same provider, different variable values.
What a boundary is
A boundary between environments is enforced by:
- State. Production and non-production do not share state.
- Credentials. Production and non-production do not share credentials.
- Account. Production and non-production do not share an AWS account.
- Network. Production and non-production are not reachable from each other on the data plane.
Each of these is a separate boundary. Removing any one of them weakens the isolation. A team that puts staging and production in the same AWS account has weakened the account boundary; the blast radius is now the account, not the environment.
When to stop adding environments
Three environments is the minimum. Some estates add more:
- Sandbox. A per-engineer disposable environment for experimentation.
- Pre-prod. A staging environment that mirrors production data volume but does not serve traffic.
- DR. A disaster-recovery environment in a different region.
Each added environment has a cost. The state is duplicated. The credentials are duplicated. The modules are exercised in N environments. The CI matrix grows. A team of three engineers with six environments will struggle; a team of thirty engineers with three environments is fine.
The trade-off is real: more environments means more places to catch a bug, but also more operational surface area. The production boundary is the line that must not be crossed without a review.
What multiple environments is not
- Not a cost optimisation. Running staging costs the company’s money. The cost is justified by the cost of failing in production.
- Not a substitute for production review. A change that passes staging still requires a production review.
- Not a substitute for unit tests. The environments test integration; they do not test individual resources.
- Not a substitute for monitoring. A change that passes staging may still degrade production under load.
The environments are one layer of defence. They are not the only layer.
What comes next
The next lesson is patterns for multi-environment estates: the directory-per-env, workspace-per-env, and branch-per-env patterns, and the trade-offs between them.
Verification
terraform workspace list(if workspaces are in use) shows the active workspaces and the current selection.ls environments/shows one directory per environment, each with its own backend configuration.- The state backend for production is in a separate account from the state backend for staging.
- The IAM role used to apply production cannot read the state bucket for dev.
terraform plan -var-file=prod.tfvarsproduces a plan that targets production resources;terraform plan -var-file=staging.tfvarsproduces a plan that targets staging resources.
Knowledge check · 6 questions
Q1. What is the primary purpose of multiple environments?
Q2. Which of these is NOT a boundary between environments?
Q3. A team of three engineers should run six environments to be safe.
Q4. What is the role of the dev environment?
Q5. Which of these are valid boundaries between production and non-production? (Select all that apply.)
Q6. A team operates dev and production in the same AWS account. A destructive change targets dev, but the state file is shared with production. What happens?
Passing score: 75%. Answers are checked in this browser.