Environments with Terraform Workspaces
I once ran terraform destroy in what I thought was the staging workspace. It was production. The workspace name in the prompt was easy to miss — (production) in parentheses between the resource count and the confirmation prompt. Twenty-three resources deleted before I hit Ctrl+C. Workspaces didn't cause the incident, but they didn't prevent it either.
Terraform workspaces create multiple state instances within a single backend configuration. terraform workspace select staging switches to a different state file; the same .tf files produce different infrastructure depending on variable values. They're lightweight environment isolation — useful for small projects, risky as a sole environment strategy for production systems.
How workspaces work
$ terraform workspace list
default
* staging
production
$ terraform workspace select production
The terraform.workspace variable returns the current workspace name:
locals {
environment = terraform.workspace
instance_type = {
staging = "t3.small"
production = "t3.large"
}
}
resource "aws_instance" "app" {
instance_type = local.instance_type[local.environment]
tags = { Environment = local.environment }
}
Same code, different resources per workspace.
Workspace-based variable files
terraform workspace select staging
terraform apply -var-file=staging.tfvars
terraform workspace select production
terraform apply -var-file=production.tfvars
Wrap in a script to prevent mismatched workspace/vars:
#!/bin/bash
ENV=$1
terraform workspace select "$ENV"
terraform apply -var-file="${ENV}.tfvars"
Workspaces vs separate directories
| Factor | Workspaces | Separate directories |
|---|---|---|
| Code duplication | None | Some — shared modules |
| Environment divergence | Awkward — conditionals | Natural |
| Access control | Shared backend | Separate backends, different IAM |
| Blast radius | One config change affects all | Scoped to one environment |
| Best for | Dev/staging identical shape | Production with different sizing |
Recommended hybrid approach
infra/
modules/ # Shared reusable modules
envs/
staging/
main.tf
backend.tf
staging.tfvars
production/
main.tf
backend.tf
production.tfvars
Both environments use the same modules. Root configs differ in variable values and possibly which modules are instantiated. State is fully isolated by backend key.
Safety guardrails
Prompt protection: Use lifecycle { prevent_destroy = true } on critical production resources.
Visual confirmation: Export PS1 to show current workspace: [tf:production].
CI/CD isolation: Separate GitHub environments with approval gates for production applies.
jobs:
apply-production:
environment: production
steps:
- run: terraform apply -var-file=production.tfvars -auto-approve
working-directory: envs/production
Production applies require explicit approval. Staging applies run automatically on merge.
Naming and tagging conventions across workspaces
When workspaces share an AWS account, enforce naming: ${var.project}-${terraform.workspace}-${var.resource}. Tags should include Environment = terraform.workspace for cost allocation. Without convention, dev and staging resources become indistinguishable in Cost Explorer and during incident response.
When to migrate off workspaces
If environments diverge in resources, provider versions, or AWS accounts, migrate to directory-per-environment with separate backend keys. Import existing resources into new state with terraform state mv or declarative import blocks. Document the migration in an ADR so teams do not reintroduce workspace sprawl for production.
Operational checklist for teams
Assign an owner for each recurring failure mode. Measure baseline before changes and compare after two sprints. Document the fix in the team wiki or runbook so the next engineer does not rediscover it. Schedule a quarterly review of metrics, tooling, and process — what reduced flakes or improved quality last quarter should be doubled down on; what did not work should be retired explicitly rather than left on the books.
Operational checklist for teams
Assign an owner for each recurring failure mode. Measure baseline before changes and compare after two sprints. Document the fix in the team wiki or runbook so the next engineer does not rediscover it. Schedule a quarterly review of metrics, tooling, and process — what reduced flakes or improved quality last quarter should be doubled down on; what did not work should be retired explicitly rather than left on the books.
Operational checklist for teams
Assign an owner for each recurring failure mode. Measure baseline before changes and compare after two sprints. Document the fix in the team wiki or runbook so the next engineer does not rediscover it. Schedule a quarterly review of metrics, tooling, and process — what reduced flakes or improved quality last quarter should be doubled down on; what did not work should be retired explicitly rather than left on the books.
Workspaces vs separate state
Terraform workspaces share backend configuration — convenient for dev/staging in one account, dangerous for prod isolation. Production should use separate state files, separate AWS accounts, and separate CI pipelines — not a workspace toggle. Workspace-based env switching tempts terraform workspace select prod from a laptop; separate backends make accidental prod apply structurally harder.
When workspaces are enough
Workspaces fit personal dev sandboxes and ephemeral preview environments in one account with identical IAM boundaries. Name workspaces explicitly — dev-alice not default. Never use workspace name as sole prod guard; combine with terraform.workspace conditionals that refuse apply when backend key matches prod pattern from unapproved CI role.
Separate AWS accounts per environment remain best practice for regulated workloads. Workspaces share IAM credentials of the runner — a compromised dev laptop with prod workspace access is game over. Structure CI so prod workspace apply requires OIDC role assumption from main branch only, with manual approval gate and plan artifact hash verification.
CI guardrails for workspace selection
Pipeline injects TF_WORKSPACE from branch name — main maps to prod workspace only on approved runner pool. Local terraform workspace select prod blocked by wrapper script outside break-glass hours.
Resources
- Terraform workspaces documentation
- terraform.workspace reference
- Recommended environment strategy — HashiCorp
- Terraform directory structure best practices
- GitHub Environments for deployment protection
terraform workspaces environments rollout
Field RUM on Android 4G. RDS Proxy where relevant. Rollback in PR.
terraform workspaces environments rollout
Field RUM on Android 4G. RDS Proxy where relevant. Rollback in PR.
Architecture decisions around terraform workspaces environments
IaC discipline for terraform workspaces environments is about state safety and blast radius. Remote state with locking, least-privilege CI roles, and plan review on every merge are non-negotiable.
For terraform workspaces environments:
- Workspaces or separate state per environment — never one state for prod+dev
- Modules version-pinned; avoid floating
maintags in prod - Drift detection on a schedule with human triage, not silent auto-apply in prod
- Policy-as-code (OPA/Sentinel) for public exposure, unencrypted disks, and open security groups
Run plan in CI with the same backend credentials pattern as apply, or you will ship surprises.
| Signal | Target | Alarm |
|---|---|---|
| Plan apply time | Team-defined SLO | Page on burn rate |
| Drift open count | Baseline − noise | Ticket if sustained |
| Failed policy checks | Budget cap | Weekly review |
Load and chaos experiments for terraform workspaces environments
Reviewers should challenge assumptions encoded in terraform workspaces environments: defaults copied from tutorials, timeouts that exceed upstream SLAs, and authz checks applied only on the primary UI path. Require a short threat or failure note in the PR when the change touches a trust boundary.
Concrete probes:
- Scenario C for terraform workspaces environments: traffic 3× baseline — prove autoscaling or shedding keeps the golden journey healthy.
- Scenario A for terraform workspaces environments: partial dependency outage — prove clients degrade gracefully and retries do not amplify load.
- Scenario B for terraform workspaces environments: bad config shipped — prove rollback within the declared RTO without data corruption.
Anti-patterns unique to terraform workspaces environments
Roll out terraform workspaces environments behind a flag or weighted route when possible. Start with internal users or a low-risk geography. Watch the signals in the table for at least one full business cycle before calling the migration done. Keep the previous path warm until error budgets stabilize.
Document the owner, the dashboard, and the single command that reverts the change. If that sentence is hard to write, the design is not ready for production traffic.
Observability cardinality around terraform workspaces environments
Detail 1 (421): for terraform workspaces environments, define the contract between producers and consumers explicitly — payload shape, timeout, and idempotency key. When observability cardinality around terraform workspaces environments becomes painful, it is usually because that contract was implicit.
I keep a short matrix: who can break terraform workspaces environments, how we detect it within five minutes, and who is paged. Update the matrix when ownership moves. Add one synthetic check that exercises the failure path, not only the happy path. Prefer checks that run continuously over quarterly manual reviews that everyone skips under deadline pressure.
If you only remember one thing about terraform workspaces environments: optimize for reversible decisions. Reversibility beats cleverness when the incident channel is busy and the blast radius is unclear.
Caching interactions with terraform workspaces environments
Detail 2 (276): for terraform workspaces environments, define the contract between producers and consumers explicitly — payload shape, timeout, and idempotency key. When caching interactions with terraform workspaces environments becomes painful, it is usually because that contract was implicit.
I keep a short matrix: who can break terraform workspaces environments, how we detect it within five minutes, and who is paged. Update the matrix when ownership moves. Add one synthetic check that exercises the failure path, not only the happy path. Prefer checks that run continuously over quarterly manual reviews that everyone skips under deadline pressure.
If you only remember one thing about terraform workspaces environments: optimize for reversible decisions. Reversibility beats cleverness when the incident channel is busy and the blast radius is unclear.
Frequently asked questions
Should I use Terraform workspaces or separate directories for environments?
Separate directories (envs/staging/, envs/production/) when environments differ significantly — different instance sizes, feature flags, or resource counts. Workspaces when environments are nearly identical and differ only in variable values (CIDR ranges, domain names). Most teams outgrow workspaces quickly because staging and production inevitably diverge. Directories scale better for teams with different access controls per environment.
Do Terraform workspaces provide security isolation?
No. Workspaces share the same backend bucket and code. A terraform workspace select production followed by terraform destroy in the wrong terminal destroys production. Workspace isolation is state isolation, not access control. For production safety, use separate state files in separate backend paths with IAM policies restricting who can write to production state.
How do I pass different values per workspace?
Use .tfvars files named per workspace (staging.tfvars, production.tfvars) and pass them with terraform apply -var-file=staging.tfvars. Or use workspace-specific variable defaults with terraform.workspace in conditionals. Avoid hardcoding environment logic scattered across resources — centralize in locals or a variables file.
Hiring a senior Android / Flutter engineer?
I architect and ship production mobile software — Kotlin, Jetpack Compose, Flutter — for robotics, EV infrastructure, fintech, and real-time systems. Open to remote roles in Europe and the US.
Get in touch →