Skip to content

Terraform_workspaces_advanced

Terraform workspaces allow you to manage multiple environments (dev, staging, prod) with a single configuration. This guide covers advanced workspace patterns and best practices.

┌─────────────────────────────────────────────────────────────────┐
│ Terraform Workspaces │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ terraform.tfstate.d │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ default/ │ │ dev/ │ │ prod/ │ │ │
│ │ │ (local) │ │ (remote) │ │ (remote) │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Terminal window
# List workspaces
terraform workspace list
# Create workspace
terraform workspace new dev
# Select workspace
terraform workspace select dev
# Show current workspace
terraform workspace show
# Delete workspace
terraform workspace delete dev
terraform.tf
terraform {
backend "local" {
# Workspaces stored locally
}
}
# Access workspace name in config
locals {
environment = terraform.workspace
}
terraform {
backend "s3" {
bucket = "terraform-state-bucket"
key = "terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
# Workspace-specific keys
workspace_key_prefix = "workspaces"
}
}
locals {
# Different values per workspace
instance_type = terraform.workspace == "prod" ? "t3.medium" : "t3.micro"
# Environment map
environment_config = {
dev = {
instance_count = 1
enable_monitoring = false
}
staging = {
instance_count = 2
enable_monitoring = true
}
prod = {
instance_count = 5
enable_monitoring = true
enable_backup = true
}
}
# Select config based on workspace
config = local.environment_config[terraform.workspace]
}
resource "aws_instance" "example" {
instance_type = local.instance_type
count = local.config.instance_count
tags = {
Environment = terraform.workspace
}
}
# Only create certain resources in specific workspaces
resource "aws_instance" "prod_only" {
count = terraform.workspace == "prod" ? 1 : 0
instance_type = "r5.2xlarge"
tags = {
Environment = "prod"
}
}
resource "aws_db_instance" "database" {
# Create only in non-default workspaces
count = terraform.workspace != "default" ? 1 : 0
identifier = "myapp-${terraform.workspace}"
tags = {
Environment = terraform.workspace
}
}
environments/dev/terraform.tfvars
environment = "dev"
instance_type = "t3.micro"
instance_count = 1
enable_monitoring = false
tags = {
Environment = "dev"
CostCenter = "dev"
}
environments/prod/terraform.tfvars
environment = "prod"
instance_type = "t3.medium"
instance_count = 5
enable_monitoring = true
tags = {
Environment = "prod"
CostCenter = "production"
}
variables.tf
variable "environment" {
description = "Environment name"
type = string
}
variable "instance_type" {
description = "EC2 instance type"
type = string
}
variable "instance_count" {
description = "Number of instances"
type = number
}
variable "enable_monitoring" {
description = "Enable CloudWatch monitoring"
type = bool
default = false
}
variable "tags" {
description = "Tags to apply to resources"
type = map(string)
}
# Use different backends per workspace
terraform {
backend "s3" {
bucket = "terraform-state-${terraform.workspace}"
key = "terraform.tfstate"
region = "us-east-1"
}
}

Or use conditional configuration:

main.tf
terraform {
# Dynamic backend based on workspace
backend "s3" {}
}
# backend.hcl (per workspace)
# dev.hcl
bucket = "terraform-state-dev"
key = "dev/terraform.tfstate"
# prod.hcl
bucket = "terraform-state-prod"
key = "prod/terraform.tfstate"
# Always use remote backend for workspaces
terraform {
backend "s3" {
bucket = "company-terraform-state"
dynamodb_table = "terraform-locks"
region = "us-east-1"
}
}
Terminal window
# Standard workspace names
terraform workspace new dev
terraform workspace new staging
terraform workspace new uat
terraform workspace new prod
Terminal window
# Apply with workspace-specific variables
terraform workspace select dev
terraform apply -var-file="environments/dev.tfvars"
terraform workspace select prod
terraform apply -var-file="environments/prod.tfvars"
locals {
common_tags = {
Environment = terraform.workspace
ManagedBy = "Terraform"
Project = var.project_name
}
}
resource "aws_instance" "example" {
# ...
tags = local.common_tags
}
name: Terraform
on:
push:
branches: [main]
pull_request:
jobs:
terraform:
runs-on: ubuntu-latest
strategy:
matrix:
workspace: [dev, staging, prod]
steps:
- uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.5.0
- name: Terraform Init
run: |
terraform workspace select ${{ matrix.workspace }} || terraform workspace new ${{ matrix.workspace }}
terraform init
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Terraform Plan
run: |
terraform plan -var-file="environments/${{ matrix.workspace }}.tfvars"
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Terraform Apply
if: github.ref == 'refs/heads/main'
run: |
terraform apply -var-file="environments/${{ matrix.workspace }}.tfvars" -auto-approve
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
  • Similar infrastructure across environments
  • Same modules with different parameters
  • State isolation needed
  • Team shares same state backend
  • Different infrastructure per environment
  • Different providers per environment
  • Complete isolation required
  • Different team ownership
├── environments/
│ ├── dev/
│ │ ├── main.tf
│ │ └── terraform.tfvars
│ ├── staging/
│ │ └── ...
│ └── prod/
│ └── ...
└── modules/
└── ...
Terminal window
# Get output from specific workspace
terraform workspace select prod
terraform output
# JSON output
terraform output -json > outputs.json
Terminal window
# Show state
terraform state show aws_instance.example
# Move state
terraform state mv aws_instance.example module.example.aws_instance.example
# Pull/push state
terraform state pull > backup.tfstate
terraform state push backup.tfstate
Terminal window
# Import into specific workspace
terraform workspace select prod
terraform import aws_instance.example i-1234567890abcdef0

Terraform workspaces enable:

  • Multi-environment management: Dev, staging, prod
  • State isolation: Separate state per environment
  • Configuration reuse: Single config, multiple environments
  • CI/CD integration: Automated deployments

Best practices:

  • Use remote backends for state safety
  • Use variable files per workspace
  • Tag resources with workspace name
  • Use consistent workspace naming
  • Consider directory-based approach for complete isolation