Command Palette

Search for a command to run...

Hectal

Mission 6.1 · Stage 6 — Environments

Workspaces vs Separate Backends

Goal: Try CLI workspaces on ShopLite, see exactly where they help and where they bite, and decide on the environment strategy for the rest of the course.

25 min Free (nothing is applied) 3 steps 1 break-it drills

By the end of this mission

  • Create and switch workspaces and see where their state is stored
  • Use terraform.workspace in expressions — and know why it's risky
  • List the trade-offs between workspaces and per-environment backends

Part 1

Understand it first

What a workspace is

A CLI workspace is a named, separate state file for the same configuration and backend. default is the one you've been using. terraform workspace new staging creates another; with the S3 backend its state lives at env:/staging/<your key>. Same code, same backend settings, different state.

It's the quickest way to get a second copy, which is why tutorials love it.

Why many teams avoid workspaces for environments

The selected workspace is invisible local state: nothing in the code or the command line says which environment you're about to change. terraform apply in the wrong workspace is one forgotten workspace select away.

Workspaces also share ONE backend and therefore one set of credentials and usually one AWS account, while prod should be isolated in its own account (Mission 6.3). Differences between environments tend to become terraform.workspace == "prod" ? ... : ... expressions scattered through the code. HashiCorp's own docs say workspaces aren't suitable for isolating environments with different credentials and access controls.

The alternative: same code, separate backend config + tfvars

Keep one root configuration, but give each environment its own backend settings file (bucket, key, even a different account's role) and its own .tfvars. You choose the environment explicitly on every command, and a wrapper script makes it one argument: ./tf prod plan. Everything that differs lives in two small, reviewable files per environment. This course uses that from Mission 6.2 on.

A third approach, one directory per environment calling a shared 'stack' module, adds per-environment module version pinning. It's common in large organisations, and you'll recognise it after Stage 5.

Two ways to get a second environmentdiagram
Rendering diagram…

Part 2

Your project after this mission · 0 files change

shoplite/
  • infra/
    • alb.tf
    • backend.tf
    • checks.tf
    • database.tf
    • ecr.tf
    • ecs.tf
    • iam.tf
    • locals.tf
    • logs.tf
    • main.tf
    • outputs.tf
    • probe.tf
    • providers.tf
    • refactors.tf
    • security.tf
    • storage.tf
    • terraform.tfvars
    • uploads.tf
    • variables.tf
    • versions.tf

Part 3

Build it, step by step

  1. 1

    Create a workspace and look around

    The new workspace has an empty state, so state list prints nothing. Nothing exists here yet.

    terminal
    $ terraform workspace list
    terraform workspace new staging
    terraform state list | wc -l
    ── expected output ──
    * default
     
    Created and switched to workspace "staging"!
     
    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.
    0
  2. 2

    See where its state would live

    The S3 backend prefixes non-default workspaces with env:/<name>/. The workspace_key_prefix setting changes the prefix, but not the fact that it's the same bucket and the same credentials.

    terminal
    $ terraform plan -var environment=staging -var vpc_cidr=10.25.0.0/16 -out=ws.tfplan >/dev/null
    aws s3 ls s3://shoplite-tfstate-c41e --recursive | grep tfstate$
    ── expected output ──
    2026-09-26 11:02:17 9214 bootstrap/terraform.tfstate
    2026-09-26 16:40:12 155 env:/staging/shoplite/dev/terraform.tfstate
    2026-09-26 16:31:08 211877 shoplite/dev/terraform.tfstate
    Note the key still says 'dev', because the backend block is shared. Workspaces can't vary the backend.
  3. 3

    Clean up the experiment

    Switch back and delete the workspace. You can't delete the workspace you're in, and Terraform refuses to delete one whose state isn't empty (this one never applied).

    terminal
    $ rm ws.tfplan
    terraform workspace select default
    terraform workspace delete staging
    ── expected output ──
    Switched to workspace "default".
    Deleted workspace "staging"!

Checkpoint — you should now have

  • ✓You've seen where workspace state lives (env:/<name>/...) in the same bucket.
  • ✓You can list three reasons not to use workspaces for dev/prod isolation.
  • ✓The staging workspace is deleted; you're back on default.

Part 4

Break it on purpose

Make each change, run the command, and read the error before revealing the diagnosis. Recognising these messages on sight is what makes you fast on a real team. Undo the change afterwards.

Break #1

Apply a second environment with the same names

In a staging workspace, run terraform apply -var vpc_cidr=10.25.0.0/16, forgetting to also change environment (it's still dev from tfvars).

terminal
$ terraform apply -var vpc_cidr=10.25.0.0/16
── what you'll see ──
...
aws_iam_role.ecs_execution: Creating...
aws_ecr_repository.api: Creating...
╷
│ Error: creating IAM Role (shoplite-dev-ecs-execution): operation error IAM:
│ CreateRole, https response error StatusCode: 409, EntityAlreadyExists: Role
│ with name shoplite-dev-ecs-execution already exists.
╵
╷
│ Error: creating ECR Repository (shoplite/api): RepositoryAlreadyExistsException:
│ The repository with name 'shoplite/api' already exists in the registry
╵

Part 5

Interview questions from this mission

01

What are Terraform CLI workspaces, and when are they appropriate?

02

How do you structure Terraform for multiple environments?

0/4 · 0%