Terraform

terraform state rm: Safely Untrack Real Infrastructure Without Destroying It (Pro Exam Guide)

2026-04-19
NicheeLab Editorial Team

terraform state rm removes a resource from state and stops Terraform from managing it. The actual infrastructure is not deleted, but the behavior of the next plan/apply changes significantly.

This guide walks through the safe production procedure, common scenarios, address-targeting tips, and how state rm differs from destroy, state mv, moved, and import — all aligned with the official Terraform documentation.

What state rm Really Does and When to Use It

terraform state rm removes the specified resource instance from the current Terraform state. The real infrastructure is not destroyed. Terraform then treats that resource as unmanaged, and if the same address still exists in HCL, the next plan will propose creating it again.

The main use cases are: (1) handing an existing resource off to manual operation, (2) cleaning up stale state for a resource that was deleted by hand, and (3) temporarily removing a resource before a module reorganization or rename. If your goal is a rename or move, state mv or a moved block is safer and more reproducible.

  • Only the tracking info in state is removed; the actual cloud resource stays in place.
  • If the HCL definition remains, the next plan/apply will try to recreate it — risking duplicate creation.
  • Confirm the address with terraform state list. Specify for_each keys and indexes exactly.
  • For renames and moves, prefer a moved block (Terraform 1.1+) or terraform state mv as a rule.

Basic operation template

terraform state list
# => check the addresses currently under management

terraform state show aws_s3_bucket.logs
# => inspect the state details

terraform state rm aws_s3_bucket.logs
# => remove from state (the bucket itself remains)

A Safe Procedure for "Untracking Without Destroying"

state rm is a powerful operation. To apply it safely, you need a backup, an impact assessment, and HCL-side consistency adjustments. In particular, running state rm while the HCL definition is still present will produce a "create" diff on the next plan and can lead to unintended duplicate creation.

The recommended production sequence is below. If the backend supports locking (S3 + DynamoDB lock, Terraform Cloud/Enterprise, etc.), the lock kicks in automatically, but make absolutely sure no parallel apply is running.

  • 1) Back up state (terraform state pull > tfstate.bak)
  • 2) Identify the target address (terraform state list / show)
  • 3) Remove the resource definition from HCL or define a clear strategy for permanently excluding it
  • 4) Use plan -refresh-only to sync the current state (apply -refresh-only with care)
  • 5) Run terraform state rm to remove the resource
  • 6) Run a normal terraform plan and verify the diff is as expected (ideally none, or minimal)

Example execution (Bash)

# 1) Back up state
terraform state pull > tfstate-$(date +%F-%H%M%S).bak

# 2) Identify the target address
terraform state list | grep aws_s3_bucket
terraform state show aws_s3_bucket.logs

# 3) Comment out/delete the resource from HCL (commit to VCS)

# 4) Sync the current state if needed
terraform plan -refresh-only

# 5) Remove from state
terraform state rm aws_s3_bucket.logs

# 6) Confirm the diff matches your intent
terraform plan

Common Real-World Scenarios and Patterns

Cleaning up after a manual delete: if the real infrastructure was deleted manually, delete the matching resource from HCL as well, and finally use state rm to clean up the leftover state entry. Running rm while HCL still defines the resource will trigger recreation, which contradicts the goal.

Handing off select resources to manual operation: remove the HCL definition or exclude it via a conditional (e.g., count=0) and then run state rm. Verify that future applies will not recreate the resource.

Module reorganization or renames: use a moved block or state mv as a rule and avoid rm. If you must remove a resource, plan the re-import up front.

  • Always confirm module / for_each addresses with terraform state list before acting.
  • State is per-workspace; rm only affects the current workspace.
  • Watch out for provider-side limits (e.g., names must be unique) — a common source of duplicate-creation errors.
  • If you want to manage it again, consider terraform import or moved / state mv.

Precise addressing for for_each and module-nested resources

# for_each keys must be quoted
terraform state rm 'aws_subnet.public["public-1a"]'

# A specific instance inside a module
terraform state rm 'module.network.aws_subnet.public["public-1a"]'

# Check the current workspace
terraform workspace show

Pitfalls and Side Effects, Visualized

Right after state rm, if the same resource definition remains in HCL, Terraform concludes "not in state = not yet created." The plan proposes a create, and the apply can produce duplicate creation or naming-collision errors.

Dependencies are largely rebuilt from HCL, so rm rarely breaks dependency resolution. However, if outputs or referencing resources point to something that no longer exists in state, you can hit errors or unknown-value propagation.

  • rm is effectively irreversible — a backup is mandatory.
  • If outputs or other resources reference the target, the plan can swing wildly.
  • On remote backends, do not manually edit state without locking (direct edits via state push/pull are discouraged).
  • To re-manage, either reattach with terraform import or migrate with moved / state mv.

The world after state rm (conceptual flow)

plan/applyread/writediff calculationHCL (layout)Dependency graph / planTerraform Stateaddress disappears: state rmProvider APIReal infrastructure

Example of unintended recreation

# resource "aws_s3_bucket" "logs" is still defined in HCL
terraform state rm aws_s3_bucket.logs
terraform plan
# => + create aws_s3_bucket.logs (possible duplicate creation / naming collision)

Addressing and the Right Way to "Move": state mv / moved / import

Addresses follow resource.type.name[index or key], and module-nested resources use module.path.resource.... A mistyped address can remove the wrong thing, so always confirm with terraform state list / show.

For renames or module moves, Terraform 1.1+ recommends declarative state migration with a moved block. At plan time the state is migrated automatically from the old address to the new one, which is reproducible and avoids the orphaning risk of rm.

  • Move: moved block (recommended, declarative) or terraform state mv (imperative)
  • Untrack: terraform state rm (keep the real resource, just stop managing it)
  • Reattach: terraform import (bring an existing resource into state)

Syntax examples: moved block, state mv, import

# moved (HCL, Terraform 1.1+)
moved {
  from = aws_s3_bucket.logs
  to   = module.logging.aws_s3_bucket.logs
}

# state mv (CLI)
terraform state mv aws_s3_bucket.logs module.logging.aws_s3_bucket.logs

# Reattach an existing resource (import)
terraform import aws_s3_bucket.logs my-logs-bucket-name

Exam Prep: Comparing Similar Commands and Key Question Patterns

The Pro exam frequently asks you to distinguish between "untrack without destroying," "what to use for a rename," and "reattaching an existing resource." state rm only stops managing the resource, destroy actually destroys it, state mv / moved migrate state, and import brings an existing resource into state.

For refresh-related operations, apply -refresh-only is the current recommendation. -target is an emergency tool for minimization, not a recommended practice for normal operations.

  • state rm doesn't touch the real resource; watch for recreation if HCL still defines it.
  • For renames / relocations, choose moved (or state mv).
  • Reattach pre-existing numbered/named assets with import.
  • refresh-only is for state sync; it doesn't introduce a configuration diff.
Command / FeatureEffect on Real InfrastructureEffect on StateMain Use Case
terraform state rmNo deletion (does not destroy)Removes the specified addressUntrack a resource, clean up stale entries
terraform destroy (including -target)Destroys the real resourceRemoved as part of destructionExplicit teardown; targeted destruction is for emergencies only
terraform state mv / moved{}Does not destroyMoves from the old address to the new oneRenames and module migrations
terraform importDoes not destroyRegisters an existing resourceAdopting hand-built assets
terraform apply -refresh-onlyDoes not destroyUpdates attributes via readsState sync and drift detection

One-liners that often appear on the exam

# "Untrack without destroying":
terraform state rm module.db.aws_db_instance.main

# "Rename / relocate":
terraform state mv aws_iam_role.app module.iam.aws_iam_role.app
# or declaratively with a moved block in HCL

# "Adopt an existing resource":
terraform import aws_eip.web eipalloc-1234567890abcdef0

Check Your Understanding

Pro

問題 1

You want to operate an existing S3 bucket manually going forward. Terraform must stop managing the bucket, and the real bucket must not be deleted. Which procedure is correct?

  1. Remove the resource from HCL and also remove it from state with terraform state rm
  2. Use terraform destroy -target to destroy the bucket and leave the HCL in place
  3. Move it to a different name with terraform state mv, then run terraform import
  4. Leave the HCL as-is and only run terraform state rm

正解: A

To untrack without destroying, the correct move is to delete the HCL definition (or disable its creation condition) and also remove it from state via state rm. D triggers recreation on the next plan, B destroys the real resource, and C is move/reattach, which does not match the requirement.

Frequently Asked Questions

I removed something with state rm by mistake. How do I get it back?

The safest option is to restore from a backed-up tfstate (use terraform state push carefully). If you have no backup but the underlying resource still exists in the cloud, prepare the matching HCL and reattach it with terraform import.

Do I need any special flags with a remote backend? What about locking?

Generally no extra flags are needed. If the backend supports locking (S3 + DynamoDB, Terraform Cloud/Enterprise, etc.), state rm honors the lock just like plan/apply. Avoid concurrent operations such as running apply in another terminal.

Can data sources also be targeted by state rm?

Data sources can appear in state but are re-read at plan time, so you usually don't need to rm them. Only do so when truly necessary, and only after confirming the address carefully.

Check what you learned with practice questions

Practice with certification-focused question sets

無料で問題を解いてみる
Author

NicheeLab Editorial Team

NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.


Related articles
Terraform

HCL Syntax: Terraform's Configuration Language (2026)

HCL2 fundamentals for Terraform — blocks, attributes, expres...

Terraform

Terraform Authoring & Operations Pro: Complete Guide (2026)

Tactics for the Terraform Pro exam — module authoring, works...

Terraform

Terraform Providers: Plugin Management Fundamentals (2026)

Provider mechanics — required_providers, versions, mirrors, ...

Terraform

Terraform Resource Blocks: Declarative Infra Units (2026)

Resource block fundamentals — addresses, references, common ...

Terraform

Terraform Data Sources: Read-Only External Data (2026)

Data source basics — declaration, refresh behavior, dependen...

Browse all Terraform articles (102)
© 2026 NicheeLab All rights reserved.