terraform workspaceの使い方と環境分離の判断基準|分割方式の比較
Terraformで2つ目の環境を作る段になると、ほぼ必ず「workspaceで分けるか、ディレクトリを分けるか」で手が止まります。コマンド自体は3つ覚えれば足りるのに、選択を誤ると本番へ検証用の変更を流す事故につながる。この記事では、workspaceがstateをどこにどう分けるのかという実体を先に押さえ、workspace・ディレクトリ分割・backend分割の3方式を運用条件で比較します。そのうえでdev・stg・prodの分離に使わない条件と使ってよい3場面を示し、既存のworkspace運用をディレクトリ分割へ移すstate移送手順まで扱います。バージョン依存の記述は2026年8月13日にHashiCorp公式ドキュメントとGitHub Releasesで確認した内容です。
まとめ:本番を含む環境分離では使わず検証用の複製に限る
結論から示します。dev・stg・prodのように認証情報やAWSアカウントを分けたい環境分離に、CLIのworkspaceは使いません。公式が「同一作業ディレクトリ内のCLIワークスペースは同じバックエンドを使うため、このシナリオに適した分離手段ではない」と明記しているとおり、バックエンドと認証が共通という制約が構造的に外せないからです。この用途の標準解はディレクトリ分割で、コードの重複はモジュール化で畳みます。
workspaceが働くのは、同じ構成をそのまま複製して短期間だけ使う場面に限られます。使い捨ての検証環境、機能ブランチごとの並行検証、レビュー用の一時的な複製。この3つです。逆に、環境ごとにインスタンス数やスペックが枝分かれし始めたら、その時点でworkspaceからは降りる。判断の分かれ目は「環境間の差分が変数の値だけで表現できるか」の一点にあります。
terraform workspaceの仕組みとstate保存先の実体
操作の前に、何が分かれて何が分かれないのかを固定します。取り違えたまま運用に乗せると、戻すコストが跳ね上がります。
defaultワークスペースと作業ディレクトリ単位で分かれるstateの実体
公式の定義は「Workspaces in the Terraform CLI refer to separate instances of state data inside the same Terraform working directory.」です。日本語にすると、同一の作業ディレクトリの中でstateデータのインスタンスだけを複数持つ仕組みになります。初期化した作業ディレクトリは、必ずdefaultという名前のワークスペース1つから始まります。
分かれるのはstateだけ。設定ファイル(.tfファイル群)もバックエンド設定も、プロバイダの認証情報も共通のままです。この非対称が、後述する採用可否のすべてを決めます。宣言的な構成管理そのものの前提はIaCとは?Infrastructure as Codeの仕組み・メリットと導入判断を解説で整理しています。
ローカルstateで作られるterraform.tfstate.dディレクトリの中身
バックエンドを設定していないローカルstateの場合、ワークスペースのstateはterraform.tfstate.dというディレクトリに格納されます。defaultのstateは従来どおり作業ディレクトリ直下のterraform.tfstateに置かれ、それ以外のワークスペースだけがこのディレクトリの下にワークスペース名のサブディレクトリを持つ、という非対称な配置になります。
ここで起きがちな事故が、terraform.tfstate.dのgitignore漏れです。stateには接続文字列やパスワードが平文で残るため、ローカルstateのまま複数ワークスペースを切ってコミットすると、機密値ごとリポジトリに載ります。stateの中身と扱いはTerraform stateとは?tfstateの構造とS3バックエンド・移動削除の安全手順で詳しく扱っています。
S3バックエンドでworkspace名が挟まる保存パスとロックの扱い
リモートバックエンドを使う場合、保存先の組み立て規則を知らないとstateを見失います。S3バックエンドでは、default以外のワークスペースのstateは「workspace_key_prefix」「ワークスペース名」「key」を順に連結したパスに置かれ、既定のプレフィックスは env: です。公式の例では、developmentというワークスペースのstateは env:/development/path/to/my/key に格納されます。
ロックの設定はワークスペースと独立です。S3バックエンドのstateロックはオプトインで、use_lockfileの既定値は false。有効にするとロックファイルが key.tflock として同じバケットに置かれ、実行ロールには s3:GetObject・s3:PutObject・s3:DeleteObject が要ります。マルチワークスペースに対応するバックエンドとして公式が挙げているのは次のものです。
- AzureRM・Consul・COS・GCS・Kubernetes
- Local・OSS・Postgres・Remote・S3
この一覧に無いバックエンドではワークスペースを切る操作自体が通りません。方式を決める前に対応状況を確認してください。
new・select・listの基本操作とCI実行で使う-or-createの書き方
コマンド体系は小さく、覚えるのは5つで足ります。事故が起きるのはコマンドの数ではなく、現在地の確認を省いたときです。
workspace new・select・listで現在地を確認する実行順
基本の流れは次の順序になります。
terraform workspace listで既存の一覧と現在地(アスタリスク付き)を確認するterraform workspace newでワークスペースを作成する(作成と同時に切り替わる)terraform workspace selectで対象へ切り替えるterraform workspace showで現在のワークスペース名だけを出力し、planの前に確かめる- 不要になったら
terraform workspace deleteで削除する
削除には条件が付きます。公式は削除対象について「it must not be your current workspace」と定めており、選択中のワークスペースは消せません。さらにリソースを追跡している状態では既定で拒否され、-forceを付けると通りますが、公式は「resources may become ‘dangling’. These are resources that physically exist but that Terraform can no longer manage.」と警告しています。手動で消して回る羽目になるので、destroy を先に済ませてから削除してください。
1.4系で追加された-or-createでCIの初回実行を止めない書き方
terraform workspace selectは、存在しないワークスペース名を指定するとエラーで止まります。CIで環境名を動的に渡す構成だと、初回実行がここで必ず落ちる。この穴を埋めるのが-or-createオプションで、公式の説明は「If the workspace that is being selected does not exist, create it. Default is false.」です。CHANGELOG v1.4.0 に「to aid in creating workspaces in automated situations」として追加が記録されています。
もう一つの手段がTF_WORKSPACE環境変数です。公式は select の代わりに使えると説明する一方、「Using this environment variable is recommended only for non-interactive usage」と用途を限定しています。手元の端末でシェルの初期化ファイルに書くのは避けてください。設定した本人が忘れ、別のワークスペースへapplyする典型的な事故になります。
terraform.workspace式で台数とタグを切り替える実装例
設定ファイル側からはterraform.workspaceで現在のワークスペース名を参照できます。公式が挙げる例は2つ。1つはインスタンス台数の切り替えで、count に terraform.workspace == “default” ? 5 : 1 と書き、既定では5台、それ以外では1台にします。もう1つはタグ付けで、Name に “web – ${terraform.workspace}” を入れて名前へ環境名を混ぜます。
使いどころはこの2種類、つまり「数」と「名前」までに留めるのが安全です。条件分岐がリソースの有無やスペック体系にまで広がると、コードを読んでも各環境の姿が分からなくなる。三項演算子が3つを超えたら、その構成はworkspace向きではありません。バックエンド設定ブロックの中でこの式は使えない点も押さえてください。
workspace・ディレクトリ分割・backend分割を運用条件で比較
方式の議論が長引く原因は、比較軸が「コードの重複」に偏ることです。実務で効くのは権限と誤操作耐性の側になります。
コード重複・認証分離・誤操作耐性・レビュー性で見る3方式の比較表
3方式を同じ軸で並べます。backend分割は、同じコードを別の作業ディレクトリに置くのではなく、バックエンド設定ファイルを実行時に切り替える方式(初期化時に設定を注入する形)を指します。
| 観点 | workspace | ディレクトリ分割 | backend分割 |
|---|---|---|---|
| コードの重複 | なし | あり(module化で圧縮) | ほぼなし |
| 認証・権限の分離 | できない | できる | できる |
| 誤操作の起きやすさ | 高い(切替を忘れる) | 低い(パスで分かる) | 中(引数依存) |
| 差分レビューのしやすさ | 低い(差分が変数側) | 高い(環境ごと明示) | 中 |
| stateの置き場 | 同一バケット内で分岐 | 環境ごとに指定 | 環境ごとに指定 |
| 向く用途 | 短期の複製・検証 | 常設のdev・stg・prod | 環境差が小さい常設環境 |
重複の少なさだけを見ればworkspaceが勝ちます。ところが認証分離の行で×が付いた時点で、本番を含む構成の候補からは外れる。これが方式選定の実質的な決着点です。
同一バックエンド・同一認証というworkspace最大の制約
公式の表明は2箇所あり、どちらも同じ結論を指しています。1つは「CLI workspaces within a working directory use the same backend, so they are not a suitable isolation mechanism for this scenario.」で、開発ステージごとに認証情報とアクセス制御を分けたいシナリオを指しています。もう1つは「Workspaces are not appropriate for system decomposition or deployments requiring separate credentials and access controls.」です。
実務での帰結は具体的です。stateが同一バケットに載るため、検証環境の担当者に読み書き権限を渡すと本番のstateにも手が届きます。stateにはRDSの接続情報やAPIキーが平文で残るので、これは本番の機密を配ることと変わりません。IAMで分けようにも、バックエンド設定が1つである以上は実行時の認証も1系統に固定されます。
ディレクトリ分割が標準解になる理由と重複コードを抑える具体手順
常設の環境を分けるなら、環境ごとにディレクトリを切り、それぞれに独立したバックエンド設定を置く形が標準解です。パスを見れば対象環境が分かり、レビューでも「prod配下の差分」として認識できる。CIのジョブも作業ディレクトリ単位で分けられるため、本番のジョブにだけ承認を挟むといった制御が素直に書けます。
弱点は記述の重複です。これはコード側で畳みます。共通部分をモジュールへ切り出し、環境ディレクトリには変数の値だけを置く構成にすれば、実質の重複は数十行に収まります。分割の粒度はTerraform moduleの分割粒度とoutput設計|自作とRegistryの判断で扱いました。環境が3階層(環境×リージョン×コンポーネント)を超えてバックエンド設定の記述まで重複し始めたら、Terraformの課題を解決するTerragruntの基本概念と導入メリットで解説しているツールで生成する選択肢に切り替えます。
dev・stg・prodでworkspaceを見送る条件と使ってよい3場面
ここは判断を言い切ります。玉虫色にすると、結局「とりあえずworkspaceで」という選択が残るためです。
本番を含む分離でworkspaceを見送る権限とアカウントの境界
次のいずれか1つでも当てはまるなら、workspaceは採用しません。第一に、環境ごとにAWSアカウントやAzureサブスクリプションを分けている場合。バックエンドが共通である以上、切り替えは実行時の認証情報頼みになり、切り替え漏れがそのまま越境デプロイになります。第二に、本番へのapplyに承認や実行者制限を掛けたい場合。第三に、環境ごとにstateの閲覧権限を分けたい場合です。
逃げ切れるのは、単一アカウントで本番相当のデータを持たず担当者も同一、という小規模構成だけ。人数が増えるか本番が顧客データを持った時点で移行対象になります。移行コストを踏まえると、最初からディレクトリ分割で始めるほうが安く付きます。
使ってよい3場面=使い捨て検証環境・並行検証・レビュー用の複製
逆に、workspaceが最短距離になる場面もあります。共通するのは「同じ構成をそのまま複製し、短期間で捨てる」という性質です。
- 使い捨ての検証環境:プロバイダのバージョン更新やモジュール改修の影響を、本番と同一コードで試して即destroyする
- 機能ブランチごとの並行検証:ブランチ名をワークスペース名にして、複数人が同時に同じ構成を立てる
- レビュー用の一時複製:planの差分だけでは判断しにくい変更を、実物を作って確認する
いずれもコードは1つ、差分は名前と台数だけ。前述の「数と名前まで」という線を守れる用途です。これらの環境は数時間から数日で消すため、権限分離が問題になりません。
select忘れによる本番applyの事故と実行前に止める仕組み
workspace運用で最も多い事故は、切り替え忘れです。ディレクトリ分割ならパスで気づけますが、workspaceは見た目が変わりません。防ぎ方は3層に分けます。手元では、シェルのプロンプトにterraform workspace showの結果を出す。CIでは、実行直前に期待するワークスペース名と実際の値を突き合わせ、不一致なら止める。-or-createを使う場合も、名前の生成元をパイプラインの変数に固定します。
3層目が構成側の防御です。破棄されると困るリソースにはprevent_destroyを付け、planの出力で削除件数が0でないときはCIを止める。事故の実害は「間違った環境へ作った」ことよりも「間違った環境で消した」ことで出ます。planの読み方と危険操作の止め方はterraform planの差分の読み方|init・apply・destroyの安全手順で扱っています。
workspace運用からディレクトリ分割へ移す手順とstateの移送
すでにworkspaceで本番を運用している場合の移行手順です。リソースを作り直さずにstateだけを移すのが原則になります。
移行前の棚卸しでworkspace一覧とstateの対応を突き合わせる
最初にやるのは棚卸しです。terraform workspace listで一覧を取り、それぞれに切り替えてterraform state listを実行し、どのワークスペースが何を持っているかを表にします。この時点で誰も使っていない検証用ワークスペースが2つ3つ見つかるのが通例で、それらは destroy してから削除し移行対象を減らします。
あわせて、コード内のterraform.workspace参照を全部拾います。ディレクトリ分割後はこの式が常にdefaultを返すので、名前やタグの生成に使っている箇所は変数へ置き換えてください。ここを見落とすと、移行後の初回planでリソース名の変更(=再作成)が提案されます。
state pullとpushで移送するときに止める範囲とCIの切り替え
移送の手順は次のとおりです。作業中は対象環境へのapplyを全面的に止めます。
- 移行元のワークスペースを選択し、
terraform state pullでstateをファイルに落とす - 環境ごとのディレクトリを作り、バックエンド設定を新しいキーで書いて初期化する
- 新ディレクトリで
terraform state pushにより、落としたstateを流し込む terraform planを実行し、差分が空になることを確認する(空でなければ設定側の差異を潰す)- CIのジョブを新しい作業ディレクトリへ向け直し、旧ワークスペースは destroy せずに削除する
4番目で差分が空にならないまま進めないでください。差分が残った状態のapplyは、既存リソースの置き換えを引き起こします。対象が数百リソースに及ぶ移行では、切り戻し手順を含めた設計を先に固めてください。こうしたIaCの構成見直しや移行の実務は、インフラ構築(AWS・Google Cloud・Azure)でも設計から運用まで請け負っています。
よくある質問
terraform workspaceについて、実務で問い合わせの多い5点をまとめました。
terraform workspaceとHCP Terraformのワークスペースは同じものですか?
別の概念です。CLIのワークスペースは、公式定義のとおり同一の作業ディレクトリ内でstateデータのインスタンスを分ける仕組みで、設定ファイルもバックエンドも共通です。一方HCP Terraformのワークスペースは「Each HCP Terraform workspace has its own Terraform configuration, set of variable values, state data, run history, and settings.」と説明されており、設定・変数セット・実行履歴まで独立して持ちます。名前が同じため議論が噛み合わなくなる箇所なので、どちらの話かを先に確認してください。
workspaceで環境ごとに別のAWSアカウントへデプロイできますか?
プロバイダ側の認証情報を実行時に切り替えればデプロイ自体は可能ですが、推奨しません。バックエンドは共通のままなので、stateは全環境分が同じバケットに集まります。公式も「separate credentials and access controls」を要する構成には適さないと明記しています。アカウントを分けている時点で、ディレクトリ分割か作業ディレクトリごとのbackend分割を選んでください。
defaultワークスペースは使わずに運用したほうがよいですか?
初期化した作業ディレクトリには必ずdefaultが存在し、削除の対象にもできません。実務では、defaultを本番用に使わず「未使用の置き場」として空のままにする運用が扱いやすくなります。公式のサンプルにも count = terraform.workspace == “default” ? 5 : 1 のように既定値を分ける書き方があり、defaultへ誤ってapplyした場合の影響を小さくしておくと安全側に倒れます。
workspaceを削除するとstateやリソースはどうなりますか?
リソースは削除されません。ワークスペースの削除はstateの削除であり、実体のクラウドリソースはそのまま残ります。公式もリソースを追跡している状態での削除を既定で拒否し、-forceを使った場合は「resources may become ‘dangling’」と警告しています。管理外になったリソースは請求だけが続くため、削除の前に destroy を完了させる順序を守ってください。
ディレクトリ分割にすると同じコードを何度も書くことになりませんか?
環境ディレクトリに置くのはバックエンド設定とモジュール呼び出しと変数値だけにすれば、1環境あたり数十行に収まります。リソース定義そのものは共通モジュールに1回書くだけです。環境×リージョンのように階層が増えてこの数十行の重複が問題になった段階で、生成ツールの導入を検討する順序になります。最初から生成ツールを入れると、学習コストのほうが先に効いてきます。
関連記事
- IaCとは?Infrastructure as Codeの仕組み・メリットと導入判断を解説:環境分離の前提になる宣言的な構成管理の考え方と導入判断を扱います。
- Terraform stateとは?tfstateの構造とS3バックエンド・移動削除の安全手順:移送で触るstateの構造とロック設定、安全な書き換え手順の解説です。
- Terraform moduleの分割粒度とoutput設計|自作とRegistryの判断:ディレクトリ分割の重複を畳むモジュール設計の判断基準です。
- terraform importで既存リソースをコード化する手順:state外に出てしまったリソースを管理下へ戻す工程を扱います。
- TerraformとGitHub ActionsでAWSのCI/CDを構築する手順:移行後のCIジョブを作業ディレクトリ単位で組み直すときの参照先です。