One Codebase, Many State Files
Terraform Workspaces let you use the same configuration files to manage multiple independent deployments, each with its own state file. The code is identical; only the state differs.
Think of it like a template document. You write the template once, then create a new copy for each customer. Each copy is independent — editing one doesn't affect the others.
Creating a new tenant means creating and selecting a new workspace, then applying with that tenant's variables — a repeatable, mechanical step for each new customer. Inside the code, the current workspace name is available directly as a local value, so a resource's tags or naming can reference it without any tenant-specific branching logic. Each workspace stores its state in a separate path in your backend (e.g., env:/client-acme/terraform.tfstate in S3).
The Trade-offs
Pros:
- Perfect state isolation. A corrupted or locked state for client-acme has zero effect on client-beta. Blast radius is one tenant.
- Safe rollouts. You can apply a new module version to one workspace, validate it, then roll it out to others.
- Simple mental model. The code is the same for every tenant; only the workspace name changes.
Cons — Automation Hell:
- No native bulk operations. Terraform has no built-in command to "apply all workspaces." Teams end up writing wrapper scripts that list every workspace and loop over them, selecting and applying each in turn — brittle by nature, since a failure partway through can skip remaining workspaces or leave the active workspace in an unexpected state.
- Drift is invisible. There's no built-in dashboard showing which workspaces are on which module version.
client-betacan silently fall 6 months behindclient-acmewith no alerts. - Workspaces are not a security boundary. All workspaces share the same backend credentials and the same Terraform Cloud/Enterprise organization. They are a state management feature, not an access control feature.