Terraform

Terraform state mv 徹底攻略: リソース移動の設計と落とし穴

2026-04-19
NicheeLab編集部

terraform state mv は、実インフラには触れず「状態ファイル内のアドレス」を移動させる専用コマンドです。リソース名の変更、モジュールへの切り出し、count/for_eachの再設計など、リファクタリング時の安全装置になります。

ただし、使い所と手順を誤ると、次回 apply で意図しない作成・破壊が起こり得ます。本稿では公式ドキュメントの挙動に基づき、実務での手順と試験で問われる要点を最小限のリスクで押さえます。

state mv の基本と前提

terraform state mv は、SOURCE アドレスから DESTINATION アドレスへ、状態上の関連付けを移すコマンドです。雲上リソースの作成・変更・削除は行いません。移動後、構成(HCL)のアドレスと状態のアドレスが一致すれば、plan は差分なしになります。

バックエンドがリモートの場合も、対応していればロックを取得しつつ状態を直接更新します。ワークスペース間やバックエンド間の移動は直接は扱えません。

  • 形式: terraform state mv [options] SOURCE DESTINATION
  • 対象: リソースインスタンス(aws_instance.example、module.net.aws_vpc.main など)
  • 動作: 状態のみを書き換える。API 呼び出しなし
  • 安全性: plan で差分ゼロを確認してから apply
  • ロック: 対応バックエンド(S3+DynamoDB など)ではロック取得

アドレス指定と代表的な移動パターン

Terraform のアドレスは、resource タイプ/名前、モジュール階層、count/for_each のインデックスで構成されます。state mv はこれらの「アドレスの変更」を安全に追従させるために使います。

代表パターンは次のとおりです。1) リソース名の変更、2) ルートからモジュールへ移動、3) count から for_each への再設計(インデックスとキーの対応付けを個別に移動)。

  • リソース名変更: aws_instance.web → aws_instance.app
  • モジュール化: aws_security_group.sg → module.network.aws_security_group.sg
  • count→for_each: aws_instance.example[0] → aws_instance.example["a"]
  • for_each のキー変更: aws_iam_role.role["old"] → aws_iam_role.role["new"]
  • データソースの移動は原則稀。必要時のみ慎重に実施

ルートからモジュールへの移動イメージ

Before (state)
  aws_security_group.sg
       |
       v
After (state)
  module.network.aws_security_group.sg

構成(HCL)
  - 以前: resource "aws_security_group" "sg" { ... }
  + 以後: module "network" { source = "./modules/network" }
          # module 内に aws_security_group.sg を定義

安全な手順とロールバック戦略

実務では、移動前にバックアップを取り、plan で差分ゼロを確認し、問題時に即時戻せる準備をします。リモートバックエンドではロックを前提に短時間で完了させます。

部分的な移動を残したまま apply しないこと。構成と状態の対応が崩れると意図せぬ再作成が発生します。

  • 事前に terraform fmt/validate/plan で構成の健全性を確認
  • 状態のバックアップ: terraform state pull > backup.tfstate
  • 移動→plan で差分ゼロを確認→コミット
  • 異常時は backup.tfstate を push して即時復元
  • チーム運用ではメンテナンスウィンドウ確保とロック確認

最小手順の例(リネームとモジュール化を順に検証)

# 状態のバックアップ
terraform state pull > backup.tfstate

# リソース名の変更
terraform state mv aws_instance.web aws_instance.app
terraform plan  # 差分なしであること

# モジュール化に伴う移動
terraform state mv aws_security_group.sg module.network.aws_security_group.sg
terraform plan  # 差分なしであること

# 問題があればロールバック例
# 1) ローカルに退避した backup.tfstate を確認
# 2) リモートでなければ: terraform state push backup.tfstate
#    リモートの場合は同等の復旧手順をチーム手順書に従って実施

moved ブロックとの違いと使い分け

Terraform 1.1+ には構成側でリネームを宣言できる moved ブロックがあります。moved は plan/apply 時に状態を自動で移す仕組みで、チームでの段階的移行や CI に馴染みます。一方、state mv は即時に状態を書き換える管理者ツールです。

設計判断として、安定したリネームやモジュール化は moved を優先し、緊急の修復やピンポイントなインスタンス単位の調整は state mv を使うのが実務的です。

  • moved は構成に履歴を残せるため再現性が高い
  • state mv は一撃で状態を直せるが、履歴は VCS のコミットメッセージ等で補う
  • 大規模変更は moved で段階的、細粒度の個別調整は state mv
観点state mvmoved ブロック注意点
適用タイミング即時に状態を更新plan/apply 時に移動moved は PR/CI で検証しやすい
変更の記録構成に残らないHCL に履歴が残る監査要件が厳しい環境は moved 優先
粒度インスタンス単位で精密に可ブロック単位で宣言的count/for_each の個別キーは state mv が得意
失敗時の復旧backup.tfstate で手動復旧plan で検出しやすいどちらも事前のバックアップは必須
学習/試験CLI オプションとアドレス指定の理解moved の構文と作用の理解使い分けを説明できること

複雑ケースの取り扱い(count/for_each 他)

count → for_each 移行では、インデックスからキーへのマッピングを1件ずつ移します。計画的に順序を決め、各移動の後に plan で差分ゼロを確認します。

ワークスペース間やバックエンド間の直接移動は非対応です。必要なら import と state rm の併用、あるいは pull/push を使った慎重な手動移送を検討します(競合・ロックに要注意)。

  • 例: terraform state mv aws_instance.example[0] aws_instance.example["a"]
  • キー決定: 安定キー(名前やID)を選び、以後不変を前提にする
  • module 間の移動は完全修了まで apply しない
  • data ブロックの移動は原則不要。状態最適化の観点でのみ実施
  • Workspace 跨ぎは直接不可。誤操作は破壊的になり得る

試験対策ポイントと実務チェックリスト

試験(プロフェッショナル相当)では、state mv の作用範囲、構成変更との関係、moved との比較、count/for_each・モジュール階層でのアドレス表記が問われやすいです。

実務では、バックアップ・ロック・段階適用・レビュー体制の4点を揃えると事故率を大きく下げられます。

  • state mv は状態のみ変更。API 呼び出しなし
  • 移動後に plan が差分ゼロなら成功
  • module.<name>.resource.type.name のフルアドレスを正確に指定
  • moved は宣言的・再現性重視、state mv は即時・手動調整向き
  • 部分移行のまま apply しない。常に一貫性を保つ

問題で確認

Pro

問題 1

既存環境で aws_security_group.sg をモジュール module.network 配下へ移しました。構成(HCL)は更新済みで、既存リソースを再作成せずに状態だけを新アドレスへ対応させたい。最も適切な対応はどれか。

  1. terraform state mv aws_security_group.sg module.network.aws_security_group.sg を実行し、plan で差分ゼロを確認する
  2. terraform import module.network.aws_security_group.sg <ID> を実行し、旧アドレスは放置する
  3. terraform taint aws_security_group.sg を実行してから apply する
  4. 構成を更新したので特に操作は不要。apply すれば自動で状態が移る

正解: A

状態のみを新アドレスへ移すには terraform state mv を使う。import は新規関連付けだが旧アドレスが残るため重複を招く。taint は再作成を誘発し要件不一致。構成更新のみでは状態は自動移動しない(例外は moved ブロック宣言時)。

よくある質問

state mv は実インフラに影響しますか?停止が必要ですか?

影響しません。状態ファイルのアドレスを書き換えるだけで、API 呼び出しは行われません。停止は不要ですが、ロック対応のバックエンドでは作業中の変更を避けるためにウィンドウを確保すると安全です.

ワークスペース間でリソースを移動したいのですが、state mv でできますか?

直接はできません。workspace 間やバックエンド間の移送は非対応です。一般には宛先で terraform import、元のワークスペースで terraform state rm を使います。pull/push を使った手動移送は競合や破損リスクが高いため、公式手順とレビューの下でのみ実施してください。

count から for_each へ移行する最良の手順は?

安定したキー設計を先に決め、count の各インデックスを for_each のキーへ 1 件ずつ terraform state mv で対応付けます。各移動の後に terraform plan で差分ゼロを確認し、途中で apply しないことが重要です。

この記事で学んだ内容を問題で確認しましょう

16,000問以上の問題で実力チェック

無料で問題を解いてみる
この記事の著者

NicheeLab編集部

データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。


関連記事
Terraform

Terraform HCL 構文の基礎:Block / Attribute / Expression を正しく使い分ける

Terraform Associate で頻出の HCL 構文を、ブロック・属性・式の3視点で整理。実務で迷いがちな書き...

Terraform

Terraform Authoring & Ops Pro: 上位資格の範囲と対策

上位レベルを想定したTerraformの設計・運用ドメインを整理し、実務で通用する対策を提示。モジュール設計、ステート運...

Terraform

Terraform Providers の基本: プラグイン型アーキテクチャを正しく使いこなす

Associate レベルで押さえるべき Provider の基礎、インストール、バージョニング、認証、エイリアス運用を...

Terraform

Terraform Resourceブロック徹底ガイド: 最小単位のリソース定義

Associateレベルで押さえるべきResourceブロックの構造、依存関係、メタ引数、ライフサイクル制御を実務目線で...

Terraform

Terraform Data Source徹底理解:既存リソースの参照で壊さず足す

Terraform Associate向けに、Data Sourceを用いた既存リソース参照の基本、選択基準、評価順序、...

Terraformの記事一覧 (101件)
© 2026 NicheeLab All rights reserved.