What a workspace is
A workspace is a named slot that holds a separate state file. The same HCL config with two workspaces builds two independent infrastructures, one per workspace.
Exactly one workspace is active at any moment. The plan, apply,
and destroy commands work only in it.
Every project always has a workspace named default. You cannot
delete it.
Commands:
terraform workspace list # list all workspaces
terraform workspace new staging # create and switch to it
terraform workspace select staging # switch to an existing one
terraform workspace show # print the active workspace name
terraform workspace delete staging # delete (switch to another workspace first)
Where the state files live
With a local backend (see tf-init-backends), the state of each
workspace is kept in a subdirectory of terraform.tfstate.d/:
myproject/
├── main.tf
├── terraform.tfstate # default workspace
└── terraform.tfstate.d/
├── staging/
│ └── terraform.tfstate
└── prod/
└── terraform.tfstate
With a remote backend (S3, GCS, Terraform Cloud) the workspace
becomes a key prefix: env:/staging/myproject and so on.
How to use the workspace name in HCL
It is available through terraform.workspace:
resource "aws_s3_bucket" "logs" { bucket = "logs-${terraform.workspace}-acme"▸"logs-default-acme", "logs-staging-acme", ...
}
This is handy for naming, but it is also risky: the same
configuration can create a different number of resources in different
workspaces through count = terraform.workspace == "prod" ? 3 : 1.
Without firm discipline, two months later nobody remembers how the
prod workspace differs from the staging workspace.
When a workspace makes sense
- Very similar copies of one and the same thing. Per-PR review environments, ephemeral test stands.
- When the infrastructure really is identical and the only difference is the resource names.
- When the team understands that a workspace is just one state per config, not an "isolated account".
When a workspace is an anti-pattern
- Prod / staging / dev. These environments usually differ in
their parameters (instance sizes, load), credentials, and access
policies. In a single HCL config it is easy to shoot yourself in
the foot: get the
terraform.workspace == "prod"variable wrong, and something meant for dev ships to prod. The better solution is a separate directory for each environment, with its own backend and its own state. - When you need different access permissions for the state. A workspace in one backend means the same set of credentials for state access. You cannot isolate who can read the prod state and who can read staging.
- Isolating the blast radius. One broken apply in the
prodworkspace, with a backend that has no locking, can damage both the state itself and the neighboring workspaces.
This is why the course uses ordinary directories instead of workspaces. A workspace is a working tool for niche scenarios.
Workspaces and the remote/local backend
- Local backend: the workspace switches a subfolder in
terraform.tfstate.d/. Everything is local. - S3 backend: the workspace becomes a key prefix.
- Terraform Cloud: the workspace is a first-class entity with its own UI, RBAC, and run history. Here it really does give you isolation.
In other words, a "workspace" in TF Cloud and a "workspace" in the local CLI are two different concepts that share a name. This confuses a lot of people.
Pitfalls
- You cannot delete
default. If you want things clean, create a new workspace and work in it;defaultstays empty. workspace deletedoes not delete resources. It only removes the state. If something is deployed in the workspace, rundestroyfirst anddeleteafter, or you will leave orphaned resources in the cloud.terraform.workspaceis available inside HCL only after a select. Through the Terraform Cloud UI there can be a nuance: the workspace is set by the run context, not by the CLI.- Environment names do not belong hardcoded in the code. In HCL
you almost never want to write
if terraform.workspace == "prod". Use a variable likeenvironment = "prod"and ordinary conditional expressions instead.