# Workspaces and environments

Run one Terraform configuration against several environments in Buddy with workspaces, separate state backends, or one pipeline per directory.

Most teams run one configuration against several environments - `dev`, `staging`, `prod`. In Buddy, you separate their states in one of three ways.

## Terraform workspaces

`tf_workspace` selects a [Terraform workspace](https://developer.hashicorp.com/terraform/language/state/workspaces). Buddy exports it as `TF_WORKSPACE` before `init`, so Terraform selects the workspace, or creates it if needed.

```yaml
- action: Plan
  type: TERRAFORM_PLAN
  tool: OPENTOFU
  version: 1.12.6
  tf_workspace: staging
```

- When `tf_workspace` is empty, the action uses the `TF_WORKSPACE` variable if it is set, and `default` otherwise.
- The workspace that actually ran is exported as `BUDDY_ACTION_TF_PLAN_WORKSPACE`.
- Use **the same `tf_workspace` in Plan and Apply**. Otherwise, Apply runs against a different state.

To use one pipeline for all environments, set `tf_workspace: $ENVIRONMENT` and pass `ENVIRONMENT` when you [run the pipeline](/docs/pipelines/parameterized-pipelines/passing-parameters-on-run.md).

<Hint type="warning">

Terraform's HTTP backend, which the [artifact backend](/docs/terraform/state.md#artifact) uses, supports only the `default` workspace. With the artifact backend, separate environments with artifact versions instead (see below).

</Hint>

## Separate backends

You can give each environment its own state instead:

- **Artifact backend:** one artifact version per environment - `artifact_version: $ENVIRONMENT`.
- **S3 or GCS:** a different `key` or `prefix` per environment. `additional_args` is only added to `plan` and `apply`, not `init`, so pass backend settings in the `TF_CLI_ARGS_init` variable, for example `-backend-config=key=staging/terraform.tfstate`.

Keep each environment's variables in a separate `.tfvars` file and pick it with `additional_args: -var-file=env/$ENVIRONMENT.tfvars`.

## Several directories in one repository

When one repository holds several root modules - `network/`, `database/`, `app/` - each one needs its own `working_directory`:

- **One pipeline per directory.** Trigger each pipeline only on changes in its directory, so a change to `app/` doesn't plan `network/`.
- **Several Plan and Apply pairs in one pipeline.** Give each Apply an explicit `plan_file_path`, because by default Apply picks up the plan from the most recent Plan action. See [The plan file](/docs/terraform/plan-and-apply.md#the-plan-file).

## Promoting a change between environments

A common setup is one pipeline per environment, run in order:

1. A push to `main` runs the `staging` pipeline: Plan → Apply.
2. When it succeeds, it [triggers](/docs/pipelines/introduction/triggering-pipelines/trigger-pipeline-action.md) the `prod` pipeline: Plan → Approve Run → Apply.

Each pipeline plans against its own state, so the production plan always reflects what's actually deployed in production.


---
Original source: https://buddy.works/docs/terraform/workspaces-and-environments