Migrating from Terraform Workspaces
Terraform workspaces solve a simple problem: deploy the same code to multiple environments using one state backend. But as your infrastructure grows, workspaces create more problems than they solve. Atmos provides a better path forward.
Why Workspaces Fall Short
Workspaces seem great at first—one command (terraform workspace select prod) and you're deploying to production. But they have fundamental limitations:
1. Shared State Backend = Single Point of Failure
All workspaces share the same backend configuration. One misconfigured workspace can corrupt state for all environments.
# ALL workspaces use this backend
terraform {
backend "s3" {
bucket = "my-terraform-state" # Same bucket for dev, staging, prod
key = "terraform.tfstate" # Workspace adds prefix, but it's fragile
region = "us-east-1"
}
}
A typo in dev can overwrite prod state. This has happened to many teams.
2. No Configuration Differentiation
Workspaces use the same variables file. You end up with massive case statements:
variables.tf
3. Hidden State
Which workspaces exist? What resources do they contain? You have to inspect the state backend or track it manually.
$ terraform workspace list
default
dev
staging
prod
old-test-workspace # Is this safe to delete?
johns-experiment # What is this?
4. No Code Reuse
Every workspace runs the exact same code. Want to test a new module version in dev before prod? Tough luck. You need to branch your entire repository.
5. Blast Radius
All environments in one state backend means one mistake can affect all environments. Separate state backends provide isolation.
How Atmos Solves These Problems
Atmos separates code (Terraform components) from configuration (stack YAML files). This gives you:
Atmos Advantages
- Isolated state - Each stack has its own backend configuration
- Environment-specific config - No giant case statements
- Visible configuration - Stacks are files you can search, version, review
- Component reuse - Share code, customize config via inheritance
- Reduced blast radius - Isolated state backends per environment
Migration Strategy
Before: Workspace-Based Setup
main.tf
Deploy:
terraform workspace select prod
terraform apply # Which VPC am I deploying? Not obvious!
After: Atmos Stacks
Step 1: Create reusable component (generic code)
components/terraform/vpc/main.tf
Step 2: Create environment-specific stacks (config)
stacks/prod.yaml
stacks/dev.yaml
Deploy:
atmos terraform apply vpc -s prod # Crystal clear: VPC in prod
atmos terraform apply vpc -s dev # VPC in dev
No workspace selection. No hidden state. Just explicit, declarative configuration.
Learn more: atmos terraform apply | atmos terraform plan
Step-by-Step Migration
1. Extract Workspace Logic
Identify all workspace-specific logic in your Terraform code:
Before:
locals {
instance_type = terraform.workspace == "prod" ? "m5.large" : "t3.small"
enable_monitoring = terraform.workspace == "prod" ? true : false
backup_retention = terraform.workspace == "prod" ? 30 : 7
}
After (convert to variables):
components/terraform/app/variables.tf
2. Create Stack Configurations
For each workspace, create a stack file:
stacks/prod.yaml
stacks/dev.yaml
3. Migrate State Backends
Critical: This step requires careful planning to avoid state loss.
Option A: Keep Workspace State (Easiest)
You can keep using workspace-based state with Atmos:
stacks/prod.yaml
This lets you migrate incrementally without touching state.
Option B: Migrate to Separate Backends (Recommended)
For better isolation, migrate each workspace to its own backend:
-
Export state from workspace:
terraform workspace select prod
terraform state pull > prod.tfstate -
Configure new backend:
stacks/prod.yaml
-
Initialize and push state:
atmos terraform init vpc -s prod
terraform state push prod.tfstate -
Verify:
atmos terraform plan vpc -s prod # Should show no changes
4. Remove Workspace Logic
Clean up your Terraform code:
Remove:
# DELETE workspace references
locals {
env = terraform.workspace # Remove
}
# DELETE workspace conditionals
count = terraform.workspace == "prod" ? 1 : 0 # Remove
Replace with variables:
variable "environment" {
description = "Environment name"
type = string
}
variable "create_feature" {
description = "Whether to create optional feature"
type = bool
default = false
}
5. Update CI/CD
Before:
# Old CI/CD
terraform workspace select $ENV
terraform plan
terraform apply -auto-approve
After:
# New CI/CD
atmos terraform plan $COMPONENT -s $STACK
atmos terraform apply $COMPONENT -s $STACK -auto-approve
GitHub Actions example:
- name: Deploy VPC
run: |
atmos terraform apply vpc -s ${{ matrix.stack }}
strategy:
matrix:
stack: [dev, staging, prod]
Handling Common Patterns
Pattern 1: Workspace-Specific Resources
Before:
resource "aws_instance" "monitoring" {
count = terraform.workspace == "prod" ? 1 : 0
# ...
}
After:
components/terraform/monitoring/main.tf
stacks/prod.yaml
stacks/dev.yaml
Pattern 2: Workspace in Tags
Before:
tags = {
Environment = terraform.workspace
}
After:
components/terraform/vpc/main.tf
stacks/prod.yaml
Pattern 3: Workspace-Specific Data Sources
Before:
data "aws_ami" "app" {
most_recent = true
filter {
name = "name"
values = [terraform.workspace == "prod" ? "prod-ami-*" : "dev-ami-*"]
}
}
After:
components/terraform/app/main.tf
stacks/prod.yaml
Migration Checklist
- Audit all
terraform.workspacereferences in code - Convert workspace conditionals to variables
- Create Atmos
atmos.yamlconfiguration - Create stack files for each workspace
- Test state migration in dev first
- Migrate state (keep workspace structure OR move to separate backends)
- Verify
atmos terraform planshows no changes - Update CI/CD pipelines
- Update team documentation
- Deprecate workspace commands
Benefits After Migration
- Explicit configuration - No hidden workspace state
- Isolated backends - Prod can't accidentally affect dev
- Environment-specific settings - No complex conditionals
- Better code review - Stack changes visible in YAML diffs
- Reusable components - Same code, different configs
- Easier testing - Deploy different component versions per stack
Common Questions
Get Help
Migrating from workspaces? We're here to help:
- Slack Community - Ask migration questions
- Office Hours - Live support for complex migrations
- GitHub Discussions - Share your migration story
Next Steps
Ready to get started?
- Quick Start - Build your first Atmos stack
- Core Concepts - Understand Atmos fundamentals
- Stack Configuration - Advanced YAML features