Terraform Workspaces vs Directories: How to Manage Environments

· 2 min read · Terraform & OpenTofu Tutorials

Several environments, one code base #

Almost every project needs the same infrastructure in several environments (dev, pre, pro). There are three common ways to do it with Terraform or OpenTofu. They all give each environment its own state; what changes is where the differences live.

Option 1: Workspaces #

A workspace is a named state inside the same backend. The code is the same and the workspace name is available as terraform.workspace.

$ tofu workspace new dev
$ tofu workspace new pro
$ tofu workspace select dev
$ tofu workspace list
main.tf
locals {
  config = {
    dev = { instance_type = "t3.micro",  count = 1 }
    pro = { instance_type = "m6i.large", count = 3 }
  }
  env = local.config[terraform.workspace]
}

resource "aws_instance" "web" {
  count         = local.env.count
  ami           = data.aws_ami.ubuntu.id
  instance_type = local.env.instance_type
}

With the S3 backend, each workspace is saved under env:/<workspace>/<key>.

Pros: no duplicated code, easy to create temporary environments. Cons: it is easy to run apply in the wrong workspace because nothing in the code or directory shows it. All workspaces share the same backend, credentials and code version, so you cannot promote a change from dev to pro gradually. They are not recommended to separate production from other environments.

Option 2: One directory per environment #

infra/
  modules/
    network/
    app/
  environments/
    dev/
      main.tf        # calls the modules with dev values
      backend.tf
    pro/
      main.tf
      backend.tf

Each environment has its own backend configuration, its own state and its own variables. Shared code lives in modules.

Pros: explicit, different backends, accounts and permissions per environment, you promote changes by updating the module version used in pro. Cons: some repeated files (backend.tf, providers.tf). Terragrunt removes most of that repetition.

Option 3: Same directory with tfvars and a backend per environment #

$ tofu init -backend-config=backends/pro.hcl -reconfigure
$ tofu plan -var-file=pro.tfvars

Pros: one copy of the code and separate states and accounts. Cons: you must remember to pass the right pair of files. Automate it in a Makefile or in the CI/CD pipeline.

Which one to use #

Need Recommendation
Separate AWS accounts for dev and pro Directories (option 2) or tfvars with a backend per environment (option 3)
Short-lived copies (a pull request preview, a test) Workspaces
Small project with identical environments Any, but prefer explicit
Large team Directories with versioned modules

The general advice of AWS best practices is to use a separate AWS account per environment, which workspaces cannot give you, because one workspace configuration uses one provider configuration.

See also project structure.

#Terraform #OpenTofu