BlogIaC

Terraform workspaces vs directories for environments

When workspaces help and when separate directories are safer for dev, staging, and prod — with the tradeoffs.

Mar 11, 2025·4 min readIntermediate·By the SecOpsLog team · command-tested

Terraform workspaces are alternate state instances inside the same backend configuration. terraform workspace select staging switches which state file Terraform reads — typically the same key prefix with a env:/staging/ path segment — without changing your .tf files. They are lightweight and built-in. They are also easy to misuse: one fat-fingered workspace select prod followed by apply with dev variables has deleted production more than once.

This note compares workspaces to the directory-per-environment pattern, shows how state keys differ, and gives a decision framework for when each approach fits. If workspaces feel abstract, solidify Terraform state concepts first — workspaces are just namespaced state, not magic environments.

Choosing workspace vs directory layout

Workspaces share code and backend config; directories share code via modules but isolate state paths and CI triggers.

1List environmentsdev, staging, prod, sandboxes2Same code?identical module, different…3Blast radius checkcan wrong workspace nuke prod?4Pick patternworkspaces OR env/ folders5Separate CI rolesprod role ≠ dev role6terraformworkspace newor cd env/prod && plan7Document selectionrunbook + shell prompt

How workspaces partition state

With an S3 backend, the default workspace uses terraform.tfstate as the key; named workspaces use env:/NAME/terraform.tfstate. All workspaces share the same backend block in code — only the active workspace changes which object Terraform reads. terraform.workspace is available in HCL for conditional logic, but heavy branching on workspace name in modules is a smell.

Shell prompts that show the active workspace (PS1 with terraform workspace show) have prevented more prod accidents than any Terraform feature. CI should pass -var-file=prod.tfvars explicitly rather than relying on a workspace selector hidden in the pipeline script. If your pipeline runs apply without echoing workspace name in the job log, fix that before the next outage postmortem.

backend.tf
terraform {
backend "s3" {
bucket = "acme-tfstate"
key = "network/terraform.tfstate"
region = "eu-west-1"
}
}
# staging state object: env:/staging/network/terraform.tfstate

Directory-per-environment alternative

Separate folders — live/prod/vpc, live/staging/vpc — each with its own backend key and often its own CI pipeline or approval gate. Code reuse comes from calling the same git-tagged module, not from switching workspaces. Prod gets a different AWS account, stricter IAM, and manual approval; dev does not share a workspace selector with prod at all.

Terragrunt and similar wrappers generate backend keys from folder paths automatically — you get directory isolation without copy-pasting key = values. The mental model stays simple: cd into the folder, run plan, the state path is implied by where you stand. That beats remembering whether you are in workspace prod or workspace production.

live/prod/vpc/main.tf
module "vpc" {
source = "git::https://git.example.com/modules/vpc.git?ref=v2.1.0"
name = "prod"
cidr = "10.10.0.0/16"
}
# State key: prod/vpc/terraform.tfstate — no workspace switch required
bash — workspace commandslive
terraform workspace list
* default
terraform workspace select staging
terraform plan -var-file=staging.tfvars
Always verify workspace name before apply
Workspaces are not isolation boundaries
Workspaces share the same backend credentials, the same `.tf` code, and often the same AWS account. They do not replace separate accounts, IAM boundaries, or approval workflows. For production, prefer separate directories, separate state keys, and separate CI roles over a workspace dropdown.
Workspaces vs directories
Use workspaces when
Ephemeral sandboxes (same account)
Identical code, small input diffs
Single team, low prod risk
Quick experiments
Use directories when
Prod in separate AWS account
Different approval gates per env
Different provider aliases/regions
Compliance requires hard separation

Where this goes next

Whichever pattern you pick, lock state remotely, scan plans with Checkov, and pin module versions. At scale, Terragrunt generates backend keys from folder paths so you get directory isolation without copy-paste. The Terraform course compares workspaces, -var-file, and multi-account layouts in practice.

Anti-pattern: one workspace per customer in multi-tenant SaaS — state files grow unbounded and blast radius is unclear. Prefer a directory or stack per tenant with explicit backend keys when tenant infra is long-lived.

Go deeper in a courseTerraformState, workspaces, modules, and safe multi-environment workflows.View course

Related posts