Terraform State Workspaces
Introduction
When working with infrastructure as code using Terraform, you'll often need to deploy similar infrastructure configurations across different environments such as development, staging, and production. Terraform workspaces provide a built-in mechanism to manage these separate environments using the same Terraform configuration files while keeping the state data completely isolated.
Workspaces allow you to create multiple instances of your infrastructure from the same configuration without having to maintain separate directories or configuration files. This approach simplifies environment management and helps prevent accidental changes to production environments.
Understanding Terraform Workspaces
What is a Workspace?
A workspace in Terraform is essentially an isolated instance of state. The default workspace is called default
, and when you run Terraform commands without specifying a workspace, you're operating in this default workspace.
Each workspace maintains its own state file, allowing you to create multiple infrastructure environments from the same configuration. Workspaces are particularly useful for:
- Managing different deployment environments (dev, staging, production)
- Testing infrastructure changes before applying to production
- Creating temporary or experimental environments
How Workspaces Store State
When using the default local backend, workspaces are stored as separate state files in the Terraform directory:
- The default workspace state is stored as
terraform.tfstate
- Other workspace states are stored as
terraform.tfstate.d/<workspace-name>/terraform.tfstate
When using a remote backend like S3, Terraform Cloud, or Terraform Enterprise, the state storage mechanism depends on the backend's implementation, but the isolation principle remains the same.
Working with Terraform Workspaces
Basic Workspace Commands
Let's explore the basic commands for working with Terraform workspaces:
# List available workspaces
terraform workspace list
# Create a new workspace
terraform workspace new dev
# Select an existing workspace
terraform workspace select prod
# Show the current workspace
terraform workspace show
# Delete a workspace
terraform workspace delete staging
Example: Creating and Switching Workspaces
Let's see how to create and manage workspaces for different environments:
# Initialize Terraform
terraform init
# Create workspaces for different environments
terraform workspace new dev
terraform workspace new staging
terraform workspace new prod
# List available workspaces
terraform workspace list
Output:
* dev
default
prod
staging
The asterisk (*) indicates the currently selected workspace (dev in this case).
Using Workspaces in Configuration
Accessing the Current Workspace Name
Terraform provides a special variable, terraform.workspace
, that contains the name of the current workspace. You can use this variable in your configurations to customize resources based on the active workspace:
resource "aws_instance" "web" {
count = terraform.workspace == "prod" ? 5 : 1
instance_type = terraform.workspace == "prod" ? "t3.medium" : "t3.micro"
tags = {
Name = "web-server-${terraform.workspace}"
Environment = terraform.workspace
}
}
In this example:
- Production environment gets 5 instances of type t3.medium
- Other environments get 1 instance of type t3.micro
- All resources are tagged with their environment name
Environment-Specific Variables
You can also use workspace-specific variable files to customize configurations:
# main.tf
provider "aws" {
region = var.region
}
resource "aws_instance" "example" {
instance_type = var.instance_type
ami = var.ami_id
tags = {
Name = "${var.project_name}-${terraform.workspace}"
Environment = terraform.workspace
}
}
# variables.tf
variable "region" {
description = "AWS region"
type = string
}
variable "instance_type" {
description = "EC2 instance type"
type = string
}
variable "ami_id" {
description = "AMI ID"
type = string
}
variable "project_name" {
description = "Project name"
type = string
default = "example-app"
}
You can then create workspace-specific .tfvars
files:
# dev.tfvars
region = "us-east-1"
instance_type = "t3.micro"
ami_id = "ami-0123456789abcdef0"
# prod.tfvars
region = "us-west-2"
instance_type = "t3.large"
ami_id = "ami-0123456789abcdef1"
Apply with:
# For development environment
terraform workspace select dev
terraform apply -var-file=dev.tfvars
# For production environment
terraform workspace select prod
terraform apply -var-file=prod.tfvars
Practical Workspace Example
Let's create a complete example of using workspaces to manage a web application infrastructure across different environments:
# main.tf
provider "aws" {
region = var.region
}
locals {
# Define environment-specific settings
env_settings = {
dev = {
instance_count = 1
instance_type = "t3.micro"
domain_name = "dev.example.com"
}
staging = {
instance_count = 2
instance_type = "t3.small"
domain_name = "staging.example.com"
}
prod = {
instance_count = 3
instance_type = "t3.medium"
domain_name = "example.com"
}
}
# Get settings for current workspace, fall back to dev if workspace not found
current_env_settings = lookup(local.env_settings, terraform.workspace, local.env_settings.dev)
}
resource "aws_instance" "web" {
count = local.current_env_settings.instance_count
ami = var.ami_id
instance_type = local.current_env_settings.instance_type
tags = {
Name = "web-${terraform.workspace}-${count.index + 1}"
Environment = terraform.workspace
Project = var.project_name
}
}
resource "aws_route53_record" "www" {
zone_id = var.route53_zone_id
name = local.current_env_settings.domain_name
type = "A"
ttl = "300"
records = aws_instance.web[*].public_ip
}
output "website_url" {
value = "http://${local.current_env_settings.domain_name}"
}
output "instance_ips" {
value = aws_instance.web[*].public_ip
}
With this configuration:
- Run
terraform workspace select dev
and apply to create the dev environment - Run
terraform workspace select staging
and apply to create the staging environment - Run
terraform workspace select prod
and apply to create the production environment
Each environment will have its own state file, with different numbers of servers and configurations.
Workspace Visualization
To better understand how workspaces organize your infrastructure, here's a diagram:
Best Practices for Terraform Workspaces
When to Use Workspaces
Workspaces are most effective when:
- You're managing different environments with minimal configuration differences
- You want a simple way to test changes before applying to production
- Your team is small and coordination is straightforward
When Not to Use Workspaces
Consider alternative approaches when:
- Environments have significant configuration differences
- You need strong separation of access controls between environments
- You're working with very large teams where coordination is complex
In these cases, using separate directories or repositories for each environment might be more appropriate.
Naming Conventions
Use consistent naming conventions for workspaces:
terraform workspace new dev
terraform workspace new staging
terraform workspace new prod
terraform workspace new feature-xyz # For feature branches
Using with CI/CD
In CI/CD pipelines, you can specify which workspace to use:
# Example GitLab CI job
deploy_dev:
stage: deploy
script:
- terraform init
- terraform workspace select dev || terraform workspace new dev
- terraform apply -auto-approve -var-file=dev.tfvars
environment:
name: development
Common Pitfalls and Solutions
Workspace Does Not Exist
If you encounter an error like:
Error: Workspace "prod" doesn't exist.
Simply create the workspace first:
terraform workspace new prod
Working in the Wrong Workspace
Always verify your current workspace before applying changes:
terraform workspace show
Consider adding environment visual indicators to your terminal prompt to help prevent mistakes.
Workspace State Management
When using workspaces with local state, remember that all workspace state files are stored in the same directory. If you delete this directory, you lose all workspace states. Consider using remote backends for better state management.
Summary
Terraform workspaces provide a powerful mechanism for managing multiple environments using the same configuration files. They allow you to:
- Maintain separate state files for different environments
- Customize resource configurations based on the active workspace
- Simplify management of development, staging, and production environments
While workspaces are not suitable for every scenario, they offer an elegant solution for many common infrastructure management challenges, especially for smaller teams and projects with similar configurations across environments.
Additional Resources
To deepen your understanding of Terraform workspaces, consider exploring:
- Terraform's official documentation on workspaces
- Remote backend configuration to improve state management
- Terraform modules for better code organization across environments
- Terraform Cloud's more advanced workspace capabilities
Exercises
- Create a basic Terraform configuration that deploys different sized AWS EC2 instances based on the workspace name.
- Modify an existing Terraform configuration to use the workspace name in resource naming and tagging.
- Set up a GitHub Actions workflow that automatically applies changes to the appropriate workspace based on the branch being merged.
- Create a configuration that uses different AWS regions for different workspaces while keeping the same resource specifications.
- Implement a solution that validates that production changes can be applied to a staging workspace before being applied to production.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)