Terraform Workspaces & Environments

Almost every team runs the same infrastructure more than once: dev, staging, and production, maybe per region or per customer. Terraform offers several ways to do that from shared code. CLI workspaces keep several state files for one configuration. Directory-per-environment layouts give each environment its own root module that calls shared modules. Platforms like HCP Terraform, Terragrunt, and Terraform Stacks add orchestration on top.

The word "workspace" is confusingly overloaded: CLI workspaces and HCP Terraform workspaces are different things. And the most convenient option isn't always the safest. This page explains the approaches and when each fits.

TL;DR

Quick Example

A directory-per-environment layout with shared modules:

And the CLI workspace alternative for ephemeral copies:

Core Concepts

CLI Workspaces

Every configuration starts in the default workspace. Creating another workspace creates a separate state in the same backend. With S3, that's under a path like env:/staging/<key>. In code, terraform.workspace returns the current name:

Limitations:

HashiCorp's own guidance: CLI workspaces aren't a suitable isolation mechanism for environments that need strong separation, such as production versus development.

Directory per Environment

Each environment is its own root module with its own backend configuration, variables, and credentials. Shared logic lives in modules, and environment roots are thin wiring. Benefits:

The cost is some duplication across environment directories, which tools like Terragrunt reduce.

Variables and tfvars

Keep environment differences in values, not logic: instance sizes, counts, CIDRs, and feature toggles in terraform.tfvars (loaded automatically) or -var-file=prod.tfvars. Branching on environment names in modules (count = var.env == "prod" ? 3 : 1) spreads environment knowledge everywhere. Pass an explicit replica_count variable instead.

HCP Terraform Workspaces

In HCP Terraform (formerly Terraform Cloud) and Terraform Enterprise, a workspace is a managed unit with its own state, variables (including sensitive ones), VCS connection, run history, permissions, and policies. Typically there's one workspace per environment × component, closer to directory-per-environment than to CLI workspaces. Projects group workspaces, and run triggers chain them.

Terragrunt and Stacks

Choosing an Approach

Best Practices

Separate Production Credentials

Production should live in its own cloud account or project, applied by a pipeline identity that only has prod access. That's much easier with separate root configurations than with workspaces sharing one backend and role.

Make the Target Environment Obvious

Put the environment in the directory path, the backend key, resource names, and tags. In CI, derive the environment from the path being changed, not from a manually selected workspace.

Promote Changes Through Environments

Pin module versions per environment and upgrade them in order: dev → staging → prod. Each environment then runs a known, tested version, and rollback is a version revert.

Clean Up Ephemeral Environments

Automate terraform destroy plus workspace deletion when a pull request closes, and run periodic sweeps for leftovers. Forgotten preview environments are a classic cloud cost leak.

Common Mistakes

Applying to the Wrong Workspace

Mitigate with a shell prompt showing the workspace, CI-only applies, and separate credentials per environment so a staging identity can't modify prod.

Environment Logic Scattered Through Modules

Copy-Pasted Environments Drifting Apart

Duplicating full configurations per environment without shared modules means fixes land in one environment and not the others. Keep environment directories thin and move real logic into versioned modules.

FAQ

Should I use Terraform workspaces for dev, staging, and prod?

Usually not with CLI workspaces. They share a backend and credentials, and the active workspace is easy to get wrong. Separate root configurations per environment, calling shared modules, give stronger isolation and clearer reviews. CLI workspaces shine for temporary, near-identical copies.

Are HCP Terraform workspaces the same as CLI workspaces?

No. An HCP Terraform workspace is a full managed unit with its own state, variables, permissions, and runs, typically one per environment and component. CLI workspaces are just multiple state files for one working directory.

How do I share values between environments?

Mostly you shouldn't; environments should be independent. For shared infrastructure (a central DNS zone, a shared network), read values through data sources or a parameter store rather than coupling states directly.

Is Terragrunt still needed?

It remains popular for large estates with many accounts and regions, though native features (moved/import blocks, terraform test, HCP Terraform Stacks) have narrowed the gap. Small and medium setups often do fine with directories, modules, and a CI pipeline.

Related Topics

References