By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.
You’re a cloud engineer managing infrastructure for a SaaS app with dev, staging, and prod environments. You need to: - Deploy the same infrastructure (VPC, EKS, RDS) across all three environments.- Keep configurations DRY (Don’t Repeat Yourself) but allow slight variations (e.g., smaller EC2 instances in dev).- Avoid state file collisions (e.g., accidentally destroying prod while working on dev).- Automate deployments without manually editing backend configs.
This is where terraform workspace and separate state files come in.- Workspaces let you reuse the same Terraform codebase with isolated state files (e.g., dev, staging, prod).- Separate state files mean completely independent Terraform projects (e.g., terraform-dev/, terraform-prod/).
terraform workspace
dev
staging
prod
terraform-dev/
terraform-prod/
Why does this matter in production?- If you mix up state files, you risk accidentally modifying prod while working on dev.- If you hardcode environment names, you’ll end up with duplicate code that’s hard to maintain.- If you don’t isolate state, a misconfigured terraform apply could wipe out critical resources.
terraform apply
Real-world scenario:You inherit a Terraform repo where all environments share a single state file. A teammate runs terraform destroy -target=aws_instance.web in dev, but because the state isn’t isolated, it deletes the prod instance too. Now you’re firefighting at 2 AM.
terraform destroy -target=aws_instance.web
var.environment
bash terraform workspace new dev # Creates a new workspace with its own state terraform workspace select dev # Switches to the dev workspace
# In terraform-prod/ terraform init -backend-config="bucket=my-tf-state-prod" ```
hcl terraform { backend "s3" { bucket = "my-tf-state" key = "terraform.tfstate" region = "us-east-1" } }
instance_type = "t3.micro"
instance_type = "m5.large"
terraform.workspace
.tfvars
resource "aws_instance" "web" { instance_type = var.instance_type[terraform.workspace] } ```
hcl terraform { backend "s3" { bucket = "my-tf-state" key = "terraform.tfstate" region = "us-east-1" dynamodb_table = "terraform-lock" # Enables locking } }
terraform_remote_state
resource "aws_instance" "app" { subnet_id = data.terraform_remote_state.vpc.outputs.subnet_id } ```
dev.tfvars
prod.tfvars
sops
vault
AWS Secrets Manager
bash terraform apply -var-file="dev.tfvars" # Applies dev-specific vars
terraform import
bash terraform import aws_instance.web i-1234567890abcdef0
✅ AWS account with admin IAM permissions✅ AWS CLI configured (aws configure) ✅ Terraform installed (terraform -v) ✅ S3 bucket for state storage (my-tf-state)
aws configure
terraform -v
my-tf-state
Goal: Deploy an EC2 instance in dev and prod using the same Terraform code but different workspaces.
mkdir terraform-workspaces && cd terraform-workspaces
main.tf
terraform { backend "s3" { bucket = "my-tf-state" key = "workspaces/terraform.tfstate" region = "us-east-1" dynamodb_table = "terraform-lock" # Enable locking } } provider "aws" { region = "us-east-1" } variable "instance_type" { default = { dev = "t3.micro" prod = "m5.large" } } resource "aws_instance" "web" { ami = "ami-0c55b159cbfafe1f0" # Amazon Linux 2 instance_type = var.instance_type[terraform.workspace] tags = { Environment = terraform.workspace } }
terraform init terraform workspace new dev terraform workspace new prod
terraform workspace select dev terraform apply -auto-approve
Verify:
aws ec2 describe-instances --filters "Name=tag:Environment,Values=dev"
terraform workspace select prod terraform apply -auto-approve
aws ec2 describe-instances --filters "Name=tag:Environment,Values=prod"
terraform workspace list terraform state list
Goal: Deploy the same EC2 instance but with completely separate Terraform projects (e.g., terraform-dev/, terraform-prod/).
mkdir -p terraform-separate/{dev,prod}
cd terraform-separate/dev
terraform { backend "s3" { bucket = "my-tf-state" key = "separate/dev/terraform.tfstate" region = "us-east-1" dynamodb_table = "terraform-lock" } } provider "aws" { region = "us-east-1" } resource "aws_instance" "web" { ami = "ami-0c55b159cbfafe1f0" instance_type = "t3.micro" tags = { Environment = "dev" } }
terraform init terraform apply -auto-approve
cd ../prod
terraform { backend "s3" { bucket = "my-tf-state" key = "separate/prod/terraform.tfstate" region = "us-east-1" dynamodb_table = "terraform-lock" } } provider "aws" { region = "us-east-1" } resource "aws_instance" "web" { ami = "ami-0c55b159cbfafe1f0" instance_type = "m5.large" tags = { Environment = "prod" } }
aws ec2 describe-instances --filters "Name=tag:Environment,Values=dev" aws ec2 describe-instances --filters "Name=tag:Environment,Values=prod"
✅ Never store secrets in .tfvars → Use AWS Secrets Manager or Vault.✅ Enable state locking (DynamoDB for S3) → Prevents race conditions.✅ Restrict IAM permissions → Use least privilege for Terraform roles.✅ Encrypt state files → Enable S3 bucket encryption and KMS.
✅ Use smaller instances in dev/staging → t3.micro vs. m5.large.✅ Tag resources by environment → Helps with cost allocation reports.✅ Clean up unused workspaces → terraform workspace delete old-env.
t3.micro
m5.large
terraform workspace delete old-env
✅ Use terraform.workspace for dynamic configs → Avoid hardcoding environment names.✅ Keep backend configs in a separate file → backend.tf (not main.tf).✅ Use terraform_remote_state sparingly → Prevents tight coupling.✅ Enforce naming conventions → project-env-resource (e.g., myapp-dev-vpc).
backend.tf
project-env-resource
myapp-dev-vpc
✅ Log all Terraform runs → Use Terraform Cloud or AWS CloudTrail.✅ Monitor state file changes → Set up S3 event notifications.✅ Use terraform plan in CI/CD → Prevents accidental destructive changes.
terraform plan
Separate state files (if environments are very different).
"How do you prevent two engineers from running terraform apply at the same time?"
Enable state locking (DynamoDB for S3).
"How do you dynamically set instance_type based on the environment?" hcl instance_type = var.instance_type[terraform.workspace]
instance_type
hcl instance_type = var.instance_type[terraform.workspace]
"What’s the risk of using terraform_remote_state?"
Challenge:You have a Terraform project using workspaces (dev, prod). A teammate accidentally runs terraform destroy in prod instead of dev. How do you recover?
terraform destroy
Solution:1. Restore from S3 versioning (if enabled): bash aws s3 cp s3://my-tf-state/workspaces/terraform.tfstate ./terraform.tfstate.backup 2. Re-import the state (if resources still exist): bash terraform workspace select prod terraform import aws_instance.web i-1234567890abcdef0 3. Prevent this in the future: - Enable S3 versioning (so you can roll back). - Use terraform plan in CI/CD (prevents accidental destroys).
bash aws s3 cp s3://my-tf-state/workspaces/terraform.tfstate ./terraform.tfstate.backup
bash terraform workspace select prod terraform import aws_instance.web i-1234567890abcdef0
Why it works:- S3 versioning lets you roll back to a previous state.- terraform import brings existing resources back under Terraform control.
terraform workspace new <name>
terraform workspace select <name>
apply
terraform workspace list
*
terraform workspace delete <name>
backend "s3"
-var-file="dev.tfvars"
dynamodb_table
Now go break something in dev (not prod) and fix it. ?
Join 4M+ learners. Unlock unlimited quizzes, wrong-answer tracking, flashcards + reminders, study guides, and 1-on-1 challenges.