Subscribe to the Spacelift Blog newsletter, Mission Infrastructure |

Sign Up ➡️

Terraform

What are Terraform Workspaces? Overview with Examples

Terraform workspaces

Terraform workspaces let you manage multiple, isolated deployments of the same infrastructure configuration, each with its own state file, without duplicating your code.

If you’ve ever needed to spin up a staging environment that mirrors production, test a config change without touching live infrastructure, or deploy the same setup across multiple AWS accounts or regions, workspaces are the feature that makes that clean and manageable.

In this article, we’ll cover everything you need to know: how workspaces work, how they compare to alternatives like Git branches and separate directories, how to manage variables across them, and the best practices you should follow to avoid common pitfalls.

If you’re new to Terraform itself, check out our introduction to Terraform first.

What is a Terraform workspace?

Terraform workspaces let you manage multiple deployments of the same configuration. When you create cloud resources using Terraform’s configuration language, they are created in the default workspace. Workspaces are a handy tool for testing configurations, offering flexibility in resource allocation, regional deployments, multi-account deployments, and more.

Terraform stores information about all managed resources in a state file. It is important to store this file in a secure location. Every Terraform run is associated with a state file for validation and reference. Any modifications to the Terraform configuration, whether planned or applied, are validated against the state file first, and the result is updated back to it.

If you are not consciously using a workspace, all of this already happens in the default workspace. Workspaces help you isolate independent deployments of the same Terraform configuration while using the same state file.

What is the difference between the Terraform environment and the workspace?

A Terraform environment typically refers to the overall infrastructure setup, including all configurations and resources that define it. A workspace, on the other hand, is a named state file that enables you to manage multiple isolated instances of the same infrastructure configuration. By keeping state files separate, workspaces help prevent conflicts and simplify the management of distinct deployments.

Check out our guide on How to Manage Multiple Terraform Environments Efficiently.

How to use the Terraform workspace command

The terraform workspace command manages multiple state environments within a single configuration, allowing teams to maintain separate infrastructure states for stages like development, staging, and production.

To begin, let’s look at the options available to us in the help:

terraform workspace --help
Usage: terraform [global options] workspace

  new, list, show, select, and delete Terraform workspaces.

Subcommands:
    delete    Delete a workspace
    list      List Workspaces
    new       Create a new workspace
    select    Select a workspace
    show      Show the name of the current workspace

The options are quite straightforward here. We can use the workspace command to list all the available workspaces and show the currently selected one. We can also create new workspaces and delete old ones. Finally, to navigate through workspaces, we use the select command.

1. Create an EC2 instance

For the sake of this blog post, let us consider a simple Terraform config that creates an EC2 instance with the configuration below. We are currently using three variables for AMI value, the type of instance to be created and the name tag.

resource "aws_instance" "my_vm" {
ami           = var.ami //Ubuntu AMI
instance_type = var.instance_type
 
tags = {
  Name = var.name_tag,
}
}

If we run terraform plan command at this point, it will show that it needs to create one resource, i.e. an EC2 instance. When the resource is created, the state file is updated with its information and other attributes.

Go ahead and create this EC2 instance. For reference, I am creating a t2.micro instance with Ubuntu 20.04 image.

Plan: 1 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + instance_id = (known after apply)
  + public_ip   = (known after apply)

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_instance.my_vm: Creating...
aws_instance.my_vm: Still creating... [10s elapsed]
aws_instance.my_vm: Still creating... [20s elapsed]
aws_instance.my_vm: Still creating... [30s elapsed]
aws_instance.my_vm: Still creating... [40s elapsed]
aws_instance.my_vm: Creation complete after 42s [id=i-07708992d1d3272c1]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

instance_id = "i-07708992d1d3272c1"
public_ip = "3.73.0.139"

As we can see from the output, the EC2 instance was successfully created. Run the plan command again, and see if Terraform wants to perform any additional actions at this point. It probably won’t.

2. Run terraform workspace show

To check the current workspace we are in, run the command below.

terraform workspace show
default

The output here shows that we are currently in the workspace named default.

3. Run terraform workspace list

To be sure that no other workspaces currently exist, run the list command as shown below.

terraform workspace list
* default

The list command lists all the currently created workspaces, including the default workspace. The start mark beside the default workspace indicates the currently selected workspace we are in.

4. Create a new workspace

Let us create another workspace and select the same. We can do this by running the new command with the desired name of the new workspace as below.

terraform workspace new test_workspace
Created and switched to workspace "test_workspace"!

You're now on a new, empty workspace. Workspaces isolate their state,
so if you run "terraform plan" Terraform will not see any existing state
for this configuration.

Here, I have selected the name of the new Terraform workspace as “test_workspace”. Note that running this command has created the new workspace and switched to it.

5. Verify the setup

We can verify this selection is made by running the show command as below.

terraform workspace show
test_workspace

Of course, another way to verify it would be to run the list command and see where the asterisk (*) is pointing to.

terraform workspace list
  default
* test_workspace

Terraform workspaces and state file

When we create a new workspace, Terraform creates a corresponding new state file in the same remote backend that is configured initially. The backend being used should also be able to support the workspaces.

In this example, we have used the AWS S3 bucket as the remote backend.

When we look at the contents of the Terraform state S3 bucket, apart from our default terraform.tfstate file, we can see that a new directory named “env:/” is created, within which another directory with the name of our workspace (test_workspace) is created. A new terraform.tfstate file is maintained at this location.

Ignore the other details in the screenshot below. The Key column is relevant here.

terraform workspaces and state file

Looking closely, the size of the default state file is considerably larger than that of the custom workspace-specific state file. This shows that the new state file is created, but it does not hold any information from the default state file. This is how Terraform creates an isolated environment and maintains its state file differently.

The contents of the test_workspace state file before running terraform apply are shown below:

{
  "version": 4,
  "terraform_version": "1.2.3",
  "serial": 0,
  "lineage": "c1aa5782-da15-419e-70f8-7024cadd0cfe",
  "outputs": {},
  "resources": []
}

As a result, if we run the plan command in the same directory now, Terraform will use the state file for the selected workspace. No resources are captured or maintained in this state file, so it will propose creating a new EC2 instance.

terraform plan
Plan: 1 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + instance_id = (known after apply)
  + public_ip   = (known after apply)

Note: The plan output does not specify the workspace information it uses during planning, so be very cautious when applying these changes, as using the wrong workspace may break the existing working environment.

Despite creating an EC2 instance with the same configuration in the default workspace, Terraform ignores it in a new workspace. This creates many possibilities for how infrastructure management may happen in various environments.

The isolated nature of the Terraform workspace is used to test modifications to the existing configuration before applying them to the critical environment, but this is just one use case.

How to delete a Terraform workspace

To delete the workspace, first select a different workspace. In our case, we go back to the default workspace and run the delete command. Terraform does not let us delete the currently selected workspace.

terraform workspace select default
Switched to workspace "default".

terraform workspace delete test_workspace
Deleted workspace "test_workspace"!

The corresponding directory structure in our S3 backend is deleted along with the state file.

delete test terraform workspace

Also, if you attempt to delete a workspace where certain resources are being managed by Terraform, it will not let you delete that workspace, suggesting using the -force option instead.

terraform workspace delete test_workspace
│ Error: Workspace is not empty
│ Workspace "test_workspace" is currently tracking the following resource instances:
│   - aws_instance.my_vm
│ Deleting this workspace would cause Terraform to lose track of any associated remote objects, which would then require you to delete them manually outside of Terraform. You should destroy these objects with
│ Terraform before deleting the workspace.
│ If you want to delete this workspace anyway, and have Terraform forget about these managed objects, use the -force option to disable this safety check.

Using the -force option may not be a good idea as we will lose track of all the resources being managed by Terraform. A better option would be to select that workspace, run the destroy command, and then attempt to delete the workspace again.

Note: The default workspace cannot be deleted.

As an additional point, if you don’t want to manage Terraform state, Spacelift can help overcome common state management issues and add several must-have features for infrastructure management. It offers an optional sophisticated state backend synchronized with the rest of the application to maximize security and convenience. Read more about the state management.

How to manage variables with Terraform workspaces

Managing variables with Terraform workspaces is essential when you need different configurations for different environments, like dev, test, stage, and prod. 

First, you need to declare the variables as you would normally do for any Terraform configuration. Providing values to these variables can be done easily by using tfvars files.

For each environment, you can declare a tfvars file:

vars_dev.tfvars
vars_test.tfvars
vars_stage.tfvars
vars_prod.tfvars

Based on the workspace you are on (let’s suppose you are on the dev workspace), you will run an apply like:

terraform apply –var-file=vars_dev.tfvars

You can also conditionally assign values to different parameters based on the workspace. Let’s take a look at an example:

locals {
  instance_type = terraform.workspace == “prod” ? “t2.large” : “t2.micro”
}

The above code will assign a t2.large value to the instance_type local variable if the workspace is prod or a t2.micro, if there is any other workspace selected.

There is also an option to set environment variables conditionally based on the workspace you are on, but this implementation uses a different scripting language (bash/powershell/python), and you will need to create the script’s logic yourself. That’s why using multiple tfvars files makes the most sense in this approach.

As a best practice, wherever possible, you should assign default values to your variables, especially when you are working with workspaces, to avoid repeating code in the tfvars files. This will make your configuration less error-prone.

Terraform workspaces interpolation

With the basics of Terraform workspaces in the background, it makes sense to apply this knowledge within Terraform configuration objects to identify the resources belonging to each workspace.

For example, the EC2 instances created with the same configuration as in the previous example are given the same name, i.e., whatever value is specified in the name_tag variable. When we look at these instances in the AWS console, it becomes difficult to quickly identify which EC2 instance belongs to which workspace.

Terraform provides an interpolation sequence to reference the value of the currently selected workspace, as shown below:

${terraform.workspace}

Let’s use this to set our name tags according to the respective workspace being selected. In the configuration below, we have set our name_tag variable with a default value of EC2. The aws_instance resource block uses this variable in combination with the workspace interpolation sequence to set different and respective names.

variable "name_tag" {
  type        = string
  description = "Name of the EC2 instance"
  default     = "EC2"
}
 
resource "aws_instance" "my_vm" {
ami           = var.ami //Ubuntu AMI
instance_type = var.instance_type
 
tags = {
  Name = format("%s_%s", var.name_tag, terraform.workspace)
}
}

Note: the format() function is used to concatenate multiple strings to for a valid name value.

We deleted the workspace from the previous section, so let’s also create a new workspace named “test” and create EC2 instances in both the workspaces – default, and test. See the console output below:

terraform workspace list
* default



terraform apply
Plan: 1 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + instance_id = (known after apply)
  + public_ip   = (known after apply)

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_instance.my_vm: Creating...
aws_instance.my_vm: Still creating... [10s elapsed]
aws_instance.my_vm: Still creating... [20s elapsed]
aws_instance.my_vm: Still creating... [30s elapsed]
aws_instance.my_vm: Creation complete after 31s [id=i-0c0a6ffa4405249d7]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

instance_id = "i-0c0a6ffa4405249d7"
public_ip = "3.122.229.252"




terraform workspace new test
Created and switched to workspace "test"!

You're now on a new, empty workspace. Workspaces isolate their state,
so if you run "terraform plan" Terraform will not see any existing state
for this configuration.



terraform apply
Plan: 1 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + instance_id = (known after apply)
  + public_ip   = (known after apply)

Do you want to perform these actions in workspace "test"?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_instance.my_vm: Creating...
aws_instance.my_vm: Still creating... [10s elapsed]
aws_instance.my_vm: Still creating... [20s elapsed]
aws_instance.my_vm: Still creating... [30s elapsed]
aws_instance.my_vm: Creation complete after 32s [id=i-0362373fe324e402f]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

instance_id = "i-0362373fe324e402f"
public_ip = "3.72.73.27"

Here, two EC2 instances were created using the same configuration but in different workspaces. To validate if the interpolation sequences worked, log in to the AWS console and verify the names of the newly created EC2 instances.

terraform workspaces - EC2 instances

As we can see, the names are set as expected, and now we can easily identify which instance belongs to which Terraform workspace.

Environment-specific resource requirements using Terraform workspaces

Using the Terraform workspace enables us to isolate the infrastructure management of production and sub-production environments, we can also leverage the workspace interpolation sequence to allocate appropriate resources to them. 

This helps us avoid the unnecessary costs of creating transient sub-production environments, as these can be the scaled-down version of the original configuration. With workspace interpolation sequence and conditions, configurations are improved, as shown below.

In the example shown below, we have used the workspace interpolation sequence to determine the number of EC2 instances to create based on the selected workspace. If the default workspace is selected, the given configuration would create three instances, and for all other workspaces, it would just create a single instance.

variable "name_tag" {
 type        = string
 description = "Name of the EC2 instance"
 default     = "EC2"
}
 
resource "aws_instance" "my_vm" {
 count         = terraform.workspace == "default" ? 3 : 1
 ami           = var.ami //Ubuntu AMI
 instance_type = var.instance_type
 
 tags = {
   Name = format("%s_%s_%s", var.name_tag, terraform.workspace, count.index)
 }
}

Furthermore, corresponding changes are made to the Name tag to include the count index to distinguish between multiple instances. When we apply this configuration in the default and test workspace (which we created in the last section), we should then be able to see the following instances with names:

  1. EC2_default_0
  2. EC2_default_1
  3. EC2_default_2
  4. EC2_test_0

Let’s repeat the steps to apply this configuration in both workspaces as described in the console output of the previous section. The screenshot below shows the corresponding EC2 instances created in default and test workspaces.

Environment-specific resource requirements using workspaces

Thus we have been able to limit the resource utilization of transient environments using interpolation sequence for Terraform workspaces. Similarly, we can leverage the concept of workspaces with more specific use cases.

What is the difference between Git branches and Terraform workspaces?

You shouldn’t confuse branches in the version control systems with Terraform workspaces. Both have different purposes.

Git branches maintain multiple versions of the same configuration used to develop new features or Terraform modules, whereas workspaces depend entirely on the state file maintained in the remote backend by Terraform.

In general, it is not recommended to use feature branches for deployments in the default workspace. The table below summarizes the impact of various combinations. It assumes that:

  1. The Terraform configuration is maintained in a Git repository
  2. Workspaces are used to create replica sets for debugging or developmental purposes
  3. The remote backend is configured for the Terraform workflow
Default workspace Test workspace
main branch This is the desired scenario. When we want to create a scaled-down replica of the existing environment for debugging or development purposes.
feature branch Strict no. Feature branches may contain configurations and modules which are still under development. So deploying this using the default workspace should be avoided at all costs. May not break the production, but would definitely interfere with someone else’s work in progress. Maybe consider creating a new workspace.

When working with Terraform, if workspaces are used, they take precedence over the version control strategy.

Terraform workspaces best practices

As discussed in the previous section, introducing workspaces in the Terraform workflow, along with existing Git practices, also increases the risk of human error. If the team is not well-versed in using workspaces and branches in conjunction, the chances of wrong infrastructure deployments are high.

  • Use workspaces for short-lived, parallel environments — not long-lived ones. They work well for pre-production validation or ephemeral testing, but aren’t designed to permanently manage separate staging or production environments. For that, separate root modules give you cleaner isolation and lower risk.
  • Always verify your active workspace before running terraform apply. Since the plan output doesn’t display the current workspace, applying changes in the wrong workspace is a real and costly mistake. Make workspace confirmation part of your team’s deployment checklist.
  • Keep workspace names consistent and meaningful. Names like dev, staging, or feature-vpc-change make it immediately clear what a workspace is for and who owns it. Avoid generic names like test1 or new.
  • Clean up workspaces when they’re no longer needed. Unused workspaces accumulate cached plugins and modules on your remote backend, creating unnecessary storage overhead. Destroy resources first, then delete the workspace.

For a broader look at improving your Terraform workflow, see our 20 Terraform Best Practices.

Limitations of Terraform workspaces

Workspaces let you quickly switch between multiple instances of a single configuration within its single backend, but they are not designed to solve all problems. 

  • No system decomposition. Workspaces alone are not a suitable tool for system decomposition because each subsystem should have its own separate configuration and backend
  • No credential isolation. CLI workspaces within a working directory use the same backend, so they are not a suitable isolation mechanism for deployments requiring separate credentials and access controls.
  • Manual variable management. When you provision infrastructure in each workspace, you usually need to manually specify different input variables to differentiate each collection. 
  • Shared by default. Workspaces are meant to be a shared resource. They are not private, unless you use purely local state and do not commit your state to version control. 

For complex, multi-environment setups, use reusable modules and represent each instance as a separate configuration with a different backend.

How to manage Terraform resources with Spacelift

Terraform is really powerful, but to achieve an end-to-end secure GitOps approach, you need a platform built for infrastructure orchestration. Spacelift goes beyond running Terraform workflows, giving you a governed, two-path deployment model and unlocking features such as:

  • Policy as code (based on Open Policy Agent) — Control how many approvals you need for runs, what kind of resources you can create, and what parameters those resources can have. You can also govern behavior when a pull request is open or merged.
  • Multi-IaC orchestration — Combine Terraform with Kubernetes, Ansible, and other infrastructure as code tools such as OpenTofu, Pulumi, and CloudFormation. Create dependencies between them and share outputs across stacks.
  • Governed developer self-service — Use Blueprints and Templates to build Golden Paths for your teams. Complete a simple form to provision infrastructure based on Terraform and other supported tools — with guardrails enforced throughout.
  • AI-powered visibility – Use Spacelift Intelligence to surface actionable insights across your stacks, runs, and resources, helping you identify issues faster and make better infrastructure decisions.
  • Integrations with third-party tools — Connect your existing tools and build policies around them. For example, see how to integrate security tools into your workflows using Custom Inputs.

Spacelift also supports private workers, so you can execute infrastructure workflows inside your own security perimeter. See the documentation for details on configuring worker pools.

You can try it for free by creating a trial account or booking a demo with one of our engineers.

Key Points

Terraform workspaces are a lightweight way to manage multiple deployments of the same configuration without duplicating code — ideal when environments are similar in structure but need isolated state. When your environments start diverging significantly, separate root modules will serve you better.

If you want to go further with state handling, policy enforcement, and team collaboration, Spacelift is worth exploring.

Note: New versions of Terraform are placed under the BUSL license, but everything created before version 1.5.x stays open-source. OpenTofu is an open-source version of Terraform that expands on Terraform’s existing concepts and offerings. It is a viable alternative to HashiCorp’s Terraform, being forked from Terraform version 1.5.6.

Automate Terraform deployments with Spacelift

Automate your infrastructure provisioning, and build more complex workflows based on Terraform using policy as code, programmatic configuration, context sharing, drift detection, resource visualization, and many more.

Start free trial

Frequently asked questions

  • What is the difference between the Terraform workspace and Terraform module?

    A Terraform workspace is an isolated instance of state within a single configuration, letting you maintain separate environments (like staging and production) without duplicating code. A Terraform module is a reusable, self-contained package of configuration files that encapsulates a set of resources. Workspaces manage state separation, while modules manage code organization and reuse.

  • Can I share state between Terraform workspaces?

    No. Each workspace maintains its own isolated state file. The isolation is what makes workspaces useful for testing and parallel deployments. If you need resources from one environment to reference another, use terraform_remote_state to read outputs from a separate state file explicitly.

  • What happens to my resources if I delete a workspace?

    Terraform will refuse to delete a workspace that still has resources tracked in its state file. You need to run terraform destroy first to remove those resources, then delete the workspace.

  • Are Terraform CLI workspaces the same as Terraform Cloud workspaces?

    Terraform CLI workspaces are a local state-isolation mechanism within a single configuration directory. Terraform Cloud workspaces are closer to separate projects, each with its own variables, permissions, run history, and configuration.

  • Do all backends support Terraform workspaces?

    No. Backends like S3, GCS, Azure Blob Storage, and Terraform Cloud support workspaces. Others, like the local backend, have limited support.

Terraform Project Structure
Cheat Sheet

Get the Terraform file & project structure

PDF cheat sheet.

terraform files cheat sheet bottom overlay
Share your data and download the cheat sheet