Managing tfstate per Environment with terraform workspace
This is a write-up about managing tfstate per environment with terraform workspace.
Addendum 2019/04/17
At the time of this addendum, workspace had many operational issues, so I am no longer using it. Please refer to the article below.
Overview
In the past, when managing Terraform tfstate,
on the 0.8 series I saw code that diligently switched the bucket per environment (stg, prod) using -backend-config.
However,
with workspace you can now store state per environment within a single bucket.
Strictly speaking, this doesn’t have to be per environment;
the idea is to manage state per set of resources, per module, and so on.
This time, to make it easy to grasp the concept, I split things up per environment.
History
- In 0.5, managed with S3
- In < 0.9, the storage location was configured with remote config
- In >= 0.9, multiple groups of resources are managed in the same directory with terraform workspace
It has become more and more convenient to use.
Prerequisites
We assume the following conditions.
- tfstate is managed in S3 via backend.tf
Migration Steps
Check tfstate with the existing terraform
- Confirm that the execution plan is as expected.
- If it differs, there is a problem to begin with — either there is already a diff from the current environment, or the tfstate could not be retrieved correctly — so fix that.
1 | $ terraform plan |
Retrieve the tfstate file
Retrieve terraform.tfstate locally.
Check its contents to make sure the resource configuration is reasonably free of issues.
- 0.8 series
1 | $ terraform remote config \ |
- 0.9 series and later
1 | macOS%$ terraform state pull > terraform.tfstate |
Upgrade to terraform 0.11.x (latest as of December 2017)
With Homebrew, just use upgrade!
1 | macOS%$ brew upgrade terraform |
Describe state management in backent.tf
If you already have it configured like this, you can skip this step. This is a particularly common way to write it.
1 | terraform { |
Creating a Workspace
- Create workspace
stg
1 | $ terraform workspace new stg |
- List of workspaces
1 | $ terraform workspace list |
Push the tfstate
1 | $ terraform state push -force .terraform/terraform.tfstate |
This pushes terraform.tfstate under the env:/stg/ directory of the S3 tfstate.bucket.
Go check it in S3 to confirm for yourself.

The key point is that it is env:, not env.
Check the Execution Plan
1 | $ terraform plan |
Confirm that the execution plan is as expected, and if there are no problems, the migration is complete.
Bonus
To run terraform with a specified version,
my current best practice is to wrap it in a Makefile so that it can be run in a one-off Container.
This makes it possible to run a specified version of terraform without depending on the local environment.
What is a one-off Container?
A one-off Container is a technique where you launch a Docker container with run --rm just to execute a single command one time.
If you wrap the Docker command in a Makefile,
you can use a specified terraform version
just by changing TERRAFORM_VERSION.
Below is an example with 0.11.1.
1 | TERRAFORM_VERSION=0.11.1 |
- Running
make init ENV=stgbundles the following together- Initialize tfstate
- Create workspace
stg - Initialize with the tfstate of the selected workspace
If you have an even better best practice, please let me know!
I hope this is helpful.

