TerraformXV · Environment Architecture and State BoundariesProduction Terraform
Terraform Workspaces: When and When Not
What you'll learn
- Use Terraform workspaces for per-developer sandboxes on a shared backend
- Recognise when workspaces actively hurt production isolation
- Avoid the workspace-select mistake
- Migrate from workspaces to per-directory layouts for production
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
Terraform workspaces are the OSS feature for managing multiple named states within a single backend. The lesson teaches what workspaces do, what they do not do, when they are the right tool, and when they actively undermine production isolation.
What workspaces are
A Terraform workspace is a named state within a single backend
configuration. Every Terraform configuration has at least one
workspace (the default). A configuration can declare more:
terraform workspace new dev
terraform workspace new staging
terraform workspace new prod
Each workspace is a distinct state file in the same bucket. The backend configuration is shared; the state is per-workspace:
s3://mycompany-terraform-state/
└── env:/
├── prod/terraform.tfstate
├── staging/terraform.tfstate
└── dev/terraform.tfstate
The workspace is selected with terraform workspace select:
terraform workspace select prod
terraform plan -var-file=prod.tfvars
The active workspace is also exposed at runtime as
terraform.workspace. The variable is useful for branching on
the workspace in the configuration:
locals {
config = {
dev = {
cidr_block = "10.10.0.0/16"
instance_type = "t3.medium"
}
staging = {
cidr_block = "10.20.0.0/16"
instance_type = "m5.large"
}
prod = {
cidr_block = "10.30.0.0/16"
instance_type = "m5.xlarge"
}
}
workspace_config = local.config[terraform.workspace]
}
What workspaces share
This is the critical list. Workspaces share:
- The backend configuration (
bucket,region,dynamodb_table). - The lock table (one DynamoDB table per backend, regardless of workspace count).
- The IAM principal used by the Terraform execution context.
- The provider configuration.
- The module sources.
A workspace is not a boundary. A workspace is a key prefix on the state file. The boundary that a workspace provides is the state boundary, which the workspace shares with every other workspace in the same backend.
A team that runs prod and staging as workspaces in the
same backend has:
- One state bucket (with two state files).
- One lock table.
- One IAM principal.
A bad apply in staging can lock the lock table, blocking a
legitimate apply in prod. A leaked credential that can read
the state bucket can read both prod/terraform.tfstate and
staging/terraform.tfstate. A misconfigured IAM role that
grants prod permissions also grants staging permissions.
When workspaces help
Workspaces are the right tool for:
Per-developer sandboxes. A team of N engineers can each have a workspace on a shared dev backend. The state files are small, the apply is fast, and the sandboxes do not interact with each other. The cost of a sandbox mistake is small.
terraform workspace new alice-dev
terraform workspace new bob-dev
terraform workspace new charlie-dev
Short-lived feature branches. A feature branch can have its own workspace for the duration of the branch. The workspace is destroyed when the branch is merged or abandoned.
terraform workspace new feature-x
terraform workspace select feature-x
Experimentation within a single environment. A team can test a refactor in a workspace without touching the production state. The workspace is the scratchpad.
terraform workspace new refactor-test
terraform workspace select refactor-test
terraform plan -target=module.network
The common property: the workspaces are short-lived, the blast radius is small, and the cost of a workspace mistake is acceptable.
When workspaces hurt
Workspaces are the wrong tool for:
Production isolation. Production needs a separate backend, separate credentials, and separate lock table. Workspaces provide none of these.
Multi-account estates. Production and non-production in different AWS accounts cannot be workspaces in the same backend - the credentials are different.
Compliance regimes that require separate audit trails. A compliance audit that requires “production state is in a separate account from non-production state” cannot be satisfied by workspaces in a single backend.
Long-lived environments with distinct operational ownership. Two environments owned by different teams need separate backends and credentials; the workspace boundary is too thin.
The workspace select mistake
The most common workspace-related incident is the
workspace select mistake. An operator intends to apply to
staging and accidentally applies to prod:
# Operator believes they are in staging
terraform workspace show
# Output: staging
# But the terminal session was opened in another directory
# and `terraform workspace select prod` was run earlier
terraform apply -var-file=staging.tfvars
# The apply runs against the prod workspace
# with staging variable values
# Result: production resources scaled to staging sizing
The mistake is silent. The plan output looks correct (because the variables are correct). The apply runs against the wrong workspace. The damage is visible only after the apply completes.
The discipline:
- The CI/CD pipeline selects the workspace explicitly. The
pipeline runs
terraform workspace select <env>before the apply. The pipeline variable is the source of truth. - The apply is gated on the workspace name. The pipeline asserts the workspace name matches the expected environment before the apply runs.
- The
-var-fileis named to match the workspace. A pipeline that selectsprodand passesstaging.tfvarsfails the assertion.
# CI/CD assertion
EXPECTED=prod
ACTUAL=$(terraform workspace show)
if [[ "$ACTUAL" != "$EXPECTED" ]]; then
echo "ERROR: workspace mismatch (expected $EXPECTED, got $ACTUAL)"
exit 1
fi
The migration to per-directory layouts
A team that has been using workspaces for production isolation should migrate to a per-directory layout. The migration is a one-time operation.
The steps:
- Snapshot the current state. Pull the state from each workspace and save it locally.
for ws in dev staging prod; do
terraform workspace select $ws
terraform state pull > $ws.tfstate
done
-
Create the per-directory layout. Move each environment to its own directory with its own backend configuration.
-
Push the state to the new backend. Use
terraform init -migrate-stateto migrate each state to its new backend.
cd envs/prod
terraform init -backend-config=prod.tfbackend -migrate-state
- Destroy the old workspaces. Once the new layout is verified, destroy the old workspaces.
terraform workspace select prod
terraform state rm $(terraform state list) # in the old root
terraform workspace delete prod
- Update the CI/CD pipeline. The pipeline now selects the directory, not the workspace.
When to keep workspaces
A team does not need to migrate away from workspaces entirely. The right pattern is:
- Workspaces for sandboxes and short-lived feature branches.
- Directories for production and non-production environments.
The combination is deliberate. The workspaces layer on top of the dev directory. The production directory has no workspaces because production isolation is enforced by the directory and backend boundaries.
infra/
├── envs/
│ ├── dev/
│ │ ├── main.tf
│ │ ├── backend.tf # S3 backend, shared with sandboxes
│ │ └── dev.tfvars
│ └── prod/
│ ├── main.tf
│ ├── backend.tf # S3 backend, separate bucket/role
│ └── prod.tfvars # NO workspaces in prod
The dev directory may have multiple workspaces
(alice-dev, bob-dev, feature-x). The prod directory has
exactly one workspace: default.
Validation
The validation commands for workspace discipline:
# List workspaces in the current backend
terraform workspace list
* default
alice-dev
bob-dev
feature-x
The active workspace is marked with *. The list should
match the intent.
# Confirm the workspace before any apply
terraform workspace show
# List the resources in the current workspace
terraform state list
The state list should match the intent of the workspace (e.g.
the prod workspace should contain production resources).
What comes next
The next lesson (in the following module) is state operations
in production: the state mv, state rm, and state import
commands that are the surgical tools for state recovery.
Verification
terraform workspace listfrom each environment directory shows the expected workspaces (ordefaultif workspaces are not in use).terraform workspace showreturns the active workspace before every apply; the CI/CD pipeline asserts the workspace name matches the expected environment.terraform state listfrom theprodworkspace shows only production resources; no staging or dev resources.- The production backend configuration is in a separate directory from the dev backend configuration; the two are not workspaces in the same backend.
- The IAM role used for production applies cannot read the state bucket used for non-production workspaces.
Knowledge check · 6 questions
Q1. What is the correct use of Terraform workspaces?
Q2. What does a workspace select mistake look like in production?
Q3. Why should production and non-production NOT be workspaces in the same backend?
Q4. A team using workspaces for production isolation should migrate to a per-directory layout.
Q5. Which of the following are correct uses of Terraform workspaces? (Select all that apply.)
Q6. A team has been using workspaces for production and staging in the same S3 backend. An auditor requires production state to be in a separate account. What is the migration plan?
Passing score: 75%. Answers are checked in this browser.