Workspaces and Environment Isolation
Once state becomes shared, the next problem is isolation. Development and production should not accidentally point at the same state, use the same credentials, or share the same blast radius.
Terraform CLI workspaces can create multiple state instances from one configuration, but they are not a universal answer to environment separation. This chapter explains what they actually do, where they help, and where separate configurations are safer.
What Is a Terraform CLI Workspace?
A Terraform CLI workspace lets one Terraform working directory use multiple state files.
Instead of:
One directory
β
βββ one stateyou can have:
One directory
β
βββ dev state
βββ staging state
βββ production stateThe configuration remains the same while the selected workspace determines which state Terraform operates against.
The default workspace is called:
defaultYou can see the current workspace with:
terraform workspace showList available workspaces:
terraform workspace listCreate one:
terraform workspace new devSwitch to another:
terraform workspace select productionWhy Workspaces Exist
Suppose you have a small infrastructure configuration that is intentionally identical across environments.
You might want:
dev
staging
productionto use the same Terraform code while maintaining separate state.
CLI workspaces can provide that separation.
The important mental model is:
Same Configuration
β
βββββββββββββΌββββββββββββ
βΌ βΌ βΌ
dev staging production
β β β
state A state B state CThe configuration is shared.
The state is separate.
Creating and Switching Workspaces
Start with the default workspace:
terraform workspace showCreate a development workspace:
terraform workspace new devCreate staging:
terraform workspace new stagingList them:
terraform workspace listYou might see:
default
* dev
stagingThe * indicates the currently selected workspace.
Switch to staging:
terraform workspace select stagingThen:
terraform workspace showreturns:
stagingTerraform commands now operate against the state associated with that workspace.
Workspace-Specific Values
The current workspace is available through:
terraform.workspaceFor example:
locals {
instance_name = "web-${terraform.workspace}"
}If the workspace is:
devthe value becomes:
web-devIf it is:
productionthe value becomes:
web-productionYou can also use a map:
variable "instance_size" {
type = map(string)
default = {
dev = "t3.micro"
staging = "t3.small"
production = "t3.medium"
}
}
resource "aws_instance" "web" {
instance_type = var.instance_size[terraform.workspace]
# ...
}This can be convenient for small configurations.
Warning
Workspace selection is part of the Terraform execution context. A command run in the wrong workspace can affect the wrong environment while still producing a completely valid Terraform plan.
Workspaces and Remote State
When using a backend that supports workspaces, the backend generally stores separate state for different CLI workspaces.
For the S3 backend, the default workspace has the configured key, while non-default workspaces use a workspace-specific path based on the backend’s workspace key prefix.
Conceptually:
S3 bucket
β
βββ default state
β
βββ dev state
β
βββ staging state
β
βββ production stateThis means workspaces can provide state separation without creating completely separate Terraform configurations.
The Major Limitation: Workspaces Are Not Security Boundaries
This is where beginners often overestimate workspaces.
A workspace gives you different state.
It does not automatically give you:
- Different AWS credentials
- Different IAM permissions
- Different Git branches
- Different approval requirements
- Different administrators
- Different backend buckets
- A hard production access boundary
For example:
workspace = dev
workspace = productioncan still use the same AWS identity if you configure them that way.
That means:
State isolation
β
Security isolationThis distinction is critical for production environments.
Environment Isolation Is Bigger Than State
A robust environment boundary may look like:
Development
βββ configuration
βββ state
βββ credentials
βββ permissions
Production
βββ configuration
βββ state
βββ credentials
βββ permissionsProduction may require:
- Different AWS accounts
- Different roles
- Different credentials
- Different state
- Different approval rules
- Fewer people with write access
A CLI workspace by itself does not provide those controls.
Separate Directories
Another common design is:
terraform/
βββ dev/
β βββ main.tf
β βββ backend.tf
βββ staging/
β βββ main.tf
β βββ backend.tf
βββ production/
βββ main.tf
βββ backend.tfEach directory can have its own state boundary and backend configuration.
This can make environment differences explicit.
For example:
dev
βββ cheaper instance sizes
production
βββ larger instances + stricter controlsThe downside is that duplicated configuration can drift.
That is where modules become useful.
You can keep reusable infrastructure in modules while maintaining environment-specific root configurations:
modules/
βββ application/
environments/
βββ dev/
βββ staging/
βββ production/Each environment can call the same module with different values.
This gives you stronger boundaries while retaining reuse.
Workspaces Versus Directories
Consider the two models.
CLI Workspaces
one configuration
β
βββ dev state
βββ staging state
βββ production stateGood when:
- Configuration is genuinely shared
- Environments differ mostly by values
- The team understands workspace selection
- Strong environment-specific permissions are not required from the workspace mechanism itself
Separate Root Configurations
dev/
staging/
production/Good when:
- Environments have meaningful configuration differences
- Production needs stricter review
- Different credentials or accounts are used
- You want environment boundaries to be visible in Git
- Different teams own different environments
Neither is universally correct.
The important question is:
What boundary do you actually need?
A Practical Environment Decision
A useful way to think about the choice is:
| Requirement | CLI Workspaces | Separate Root Configurations |
|---|---|---|
| Same configuration | Excellent | Possible through modules |
| Separate state | Yes | Yes |
| Different credentials | Not inherently | Easy |
| Different AWS accounts | Possible, but requires care | Natural |
| Different approval policy | Not inherently | Easier |
| Strong production boundary | Weak | Stronger |
| Small repeated environments | Convenient | More files |
| Large organizational separation | Usually awkward | Usually clearer |
CLI Workspaces and HCP Terraform Workspaces Are Different
The word “workspace” is overloaded.
Terraform CLI workspaces are local Terraform functionality. HCP Terraform workspaces are objects managed by HCP Terraform. They are not interchangeable.
A CLI workspace means multiple state instances associated with one Terraform working directory.
An HCP Terraform workspace is more like a managed unit containing configuration, variables, state, runs, permissions, and execution settings.
HashiCorp explicitly distinguishes the two. HCP Terraform workspaces are required for managing infrastructure in HCP Terraform and participate in its access-control model, while CLI workspaces are optional and isolate multiple state files within a working directory.
When CLI Workspaces Are a Good Fit
Imagine a small service deployed to several nearly identical temporary environments:
feature-a
feature-b
feature-cThe infrastructure structure is almost identical.
Workspaces can be convenient because you can create and destroy state instances without duplicating the root configuration.
Another reasonable case is a small team with several identical low-risk environments where the workspace mechanism is well understood.
When Not to Use CLI Workspaces
Be cautious when:
- Production requires separate credentials
- Production has different administrators
- Environments use different cloud accounts
- Configuration differs substantially
- Accidental workspace selection would be dangerous
- Different environments need independent CI/CD pipelines
- The state boundary needs to map directly to organizational ownership
In those situations, separate root configurations are often clearer.
A Production Mental Model
Do not think:
production = workspace "production"Think:
Production
β
βββ state boundary
βββ cloud-account boundary
βββ credential boundary
βββ permission boundary
βββ approval boundary
βββ operational ownershipA workspace can be one part of that design.
It is not the whole design.
The Goal of Environment Isolation
The purpose of environment separation is to reduce blast radius.
If development breaks:
development
β
βββ failureyou want the failure to remain there.
If production state, credentials, and infrastructure are all separated appropriately:
development ββXββ productionthen an accidental development operation has fewer ways to affect production.
That is much more valuable than simply having three different state filenames.
What Comes Next?
Once multiple environments exist, the Terraform repository itself becomes part of the operational system.
You now need to answer questions such as:
- What should Git contain?
- What must never be committed?
- Where should secrets come from?
- What does
sensitive = trueactually protect?
Those are the problems addressed in the next chapter.