Terraform workspaces are a feature that lets you manage multiple distinct states for a single configuration, effectively allowing you to run the same Terraform code against different environments (like dev, staging, prod) without duplicating your entire codebase.
Let’s see it in action. Imagine you have a simple Terraform configuration for deploying a single AWS S3 bucket.
# main.tf
resource "aws_s3_bucket" "example" {
bucket = "my-unique-app-bucket-${terraform.workspace}"
acl = "private"
tags = {
Environment = terraform.workspace
}
}
Normally, if you wanted a bucket for dev and one for prod, you might create dev.tfvars and prod.tfvars and pass them in. But workspaces give you a more integrated way to manage this.
First, you initialize Terraform:
terraform init
Now, you can create your first workspace, let’s call it dev:
terraform workspace new dev
This command creates a new state file specifically for the dev workspace. When you run terraform apply now, it will create resources tagged with dev and use a state file named terraform.tfstate.d/dev/terraform.tfstate.
Let’s apply it:
terraform apply -auto-approve
You’ll see an S3 bucket created, and its name will include dev (e.g., my-unique-app-bucket-dev).
Now, switch to another workspace, say staging:
terraform workspace new staging
And apply again:
terraform apply -auto-approve
This time, Terraform will create a separate S3 bucket, named my-unique-app-bucket-staging, and manage its state independently in terraform.tfstate.d/staging/terraform.tfstate. You now have two S3 buckets, deployed by the exact same main.tf file, but isolated by their workspace.
The core problem workspaces solve is managing multiple, distinct deployments of the same infrastructure configuration. Instead of creating separate directories for dev, staging, and prod with duplicated .tf files, you can use a single configuration. The terraform.workspace variable is the key. It’s a built-in Terraform variable that evaluates to the name of the currently selected workspace. You can use this variable directly in your resource definitions, as shown with the bucket name and the Environment tag, to make your resources environment-specific.
When you select a workspace with terraform workspace select <workspace_name>, Terraform internally switches which state file it’s reading from and writing to. This is why terraform plan and terraform apply operate on the correct, isolated state for that environment. The state files are stored locally in a directory called terraform.tfstate.d within your project, with subdirectories for each workspace. If you’re using remote state backends (like S3, Azure Blob Storage, or GCS), Terraform will manage separate state "keys" or "paths" for each workspace, ensuring complete isolation.
The real power comes when you have complex infrastructure. Imagine a Kubernetes cluster, a database, and a set of application services. With workspaces, you can define all of this once in your Terraform code and then deploy identical, but isolated, stacks for each environment. This drastically reduces duplication and the potential for configuration drift between environments.
The mental model to hold is that each workspace is a pointer to a unique state file. Terraform’s core operations (plan, apply, destroy, etc.) are then performed against that specific state file. The terraform.workspace variable acts as a dynamic parameter that your configuration can read to adapt its behavior (like naming resources or setting tags) based on the active workspace.
Many users assume that terraform workspace commands are just about state file naming. What’s actually happening under the hood is that Terraform is updating its internal context, including the workspace variable, and ensuring that all subsequent CLI commands are directed at the correct, isolated state file managed by the backend. This context switch is what enables the isolation and allows a single configuration to manage multiple distinct deployments.
The next concept you’ll likely explore is how to manage environment-specific variables more robustly, possibly using tfvars files in conjunction with workspaces or exploring Terraform modules for more complex, reusable infrastructure patterns.