Terraform

Mastering terraform destroy Safely: Practical Patterns for Full Deletion and Targeted Removal

2026-04-19
NicheeLab Editorial Team

terraform destroy uses state to unwind the dependency graph and delete managed resources. It is convenient, but misuse can cause major outages. This article organizes safe deletion and proper use of targeted removal so you can pick it up quickly from both exam and operational angles.

The first half covers safe-confirmation flows and -target caveats; the second half covers guardrail setup, workspaces, and how to handle failures. The syntax and behavior align with stable features in the official Terraform documentation.

Start Here: The destroy Flow and a Safe Confirmation Process

terraform destroy proceeds through three stages: plan → confirm → apply. The plan stage determines the deletion order from current state and configuration and computes the sequence of delete requests to providers. The confirm stage proceeds based on the interactive prompt or whether -auto-approve is present. The apply stage executes deletions according to the dependency graph.

The basics of safety are: make the plan visible before deletion, back up state, and confirm locking. On top of that, minimize the scope of what actually gets deleted, and split the order with targeted removal when needed.

  • Always plan first: terraform plan -destroy (planning only; infrastructure does not change)
  • Back up state: terraform state pull > state-backup.json
  • Locking is enabled by default for remote backends. As a rule, do not use -lock=false
  • Data sources are not subject to destroy. Only managed resources are deletion targets
  • Strictly follow the module.name.resource.type[index] form for addresses inside modules

Dependency graph and deletion order (example)

aws_iam_role.appaws_lambda_function.fndepends_on: iam_roleaws_api_gateway_rest_apiDependent (not included when targeted)Dependencies (top → bottom is depends_on). Full deletion unwinds from the bottom up. Note that -target=lambda does not include the upstream API Gateway that depends on it

Standard practice for safe pre-checks and backups

terraform workspace show
terraform state pull > state-backup-$(date +%Y%m%d%H%M%S).json
terraform plan -destroy -out=tfplan
terraform show tfplan

Using -target Correctly and the Pitfalls

-target is an advanced option that limits the plan's search scope. The official recommendation is to use it only for exceptional cases like emergency workarounds or staged deletion. Dependents (upstream resources that depend on the target) are not included in the plan, which can cause orphaning or temporary outages.

You can combine multiple -target flags. Resources accessed via modules or with count/for_each require exact address syntax. If you mistakenly remove via state rm, the cloud-side entity remains and drift increases.

  • Always confirm the impact scope with plan -destroy -target=... before use
  • Dependents are not included automatically. Plan to tear down in stages from the top down
  • Use only as a temporary measure. Do not treat it as a substitute for permanent partial application
  • Address resources exactly, like module.app.aws_iam_role.this or aws_subnet.public[0]
  • If you make a mistake, recover with import, then re-plan before proceeding

Example of staged deletion (minimizing impact)

# First, separate the most-related upstream resources
terraform plan -destroy -target=aws_api_gateway_rest_api.main -out=tfplan1
terraform destroy -target=aws_api_gateway_rest_api.main -auto-approve

# Next, delete the execution layer
terraform plan -destroy -target=aws_lambda_function.fn -out=tfplan2
terraform destroy -target=aws_lambda_function.fn -auto-approve

# Finally, the foundational permissions
terraform destroy -target=aws_iam_role.app -auto-approve

Comparing Full Deletion, Partial Deletion, and State Operations

Each deletion approach has its own characteristics. For the Associate exam, it is important to identify which approach actually deletes infrastructure and which only changes state.

In operations, the safe order is: first the orthodox path (full-deletion plan → apply), then targeted removal only when unavoidable, and import/state operations carefully when resolving drift or eliminating duplicate management.

  • Exam point: state rm does not delete cloud entities
  • Targeted removal is an exception measure, unsuitable for permanent partial operations
  • Visualize with plan beforehand and check the diff afterward
MethodScope of effectMain benefitsRisks / cautions
terraform destroyAll managed resourcesBulk deletion in a safe order along the dependency graphRisk of running against the wrong environment. Always verify workspace and plan
terraform destroy -target=addrThe specified address plus required dependenciesLocalizes impact and lets you stage the orderDependents are not included, risking orphaning. Not recommended for permanent operations
terraform state rm addrTerraform state onlyUseful for resolving mis-registration or duplicate managementThe cloud entity remains, causing drift
Manual deletion via cloud consoleOnly the target resource (external operation)Responds immediately when emergency stop or forced action is neededState drifts; import/refresh is needed afterward

Typical full-deletion flow

terraform workspace select staging
terraform plan -destroy -var-file=staging.tfvars -out=tfplan
terraform show tfplan
terraform destroy -auto-approve -var-file=staging.tfvars

Guardrail Design: Ensuring Deletion Safety with prevent_destroy

The lifecycle prevent_destroy attribute blocks deletion of the target resource at the plan stage. It is the last line of defense protecting must-protect resources (KMS keys, shared VPCs, state-backing S3, etc.) from mistakes. It cannot be bypassed by -target or -auto-approve. Removing it requires a code change and a re-plan.

create_before_destroy reduces downtime during replacement. It is not about the safety of deletion itself, but is used as an option to improve availability during replacement. Combine it with cloud-side deletion protection (e.g., S3 bucket deletion protection, RDS deletion protection, IAM policies).

  • prevent_destroy: required for irreversible core resources
  • create_before_destroy: create first during replacement to make the switchover safe
  • Use provider-specific options like force_destroy as a last resort, mindful of side effects
  • Limit who can run destroy via permission design (least privilege)

Basic protection patterns (example: protecting a critical bucket)

resource "aws_s3_bucket" "state" {
  bucket = "org-terraform-state"
  lifecycle {
    prevent_destroy = true
  }
}

# Example prioritizing availability during replacement
resource "aws_lb" "app" {
  # ...
  lifecycle {
    create_before_destroy = true
  }
}

Prevent Mishaps with Per-Workspace / Per-Environment Operations

Workspaces isolate state per environment. Always confirm the current workspace before destroy, and use environment-specific variable files to make configuration differences explicit. With a remote backend, locking is enabled by default, preventing concurrent runs.

In CI/CD, avoid routine use of -auto-approve and put approval gates in place as the default. When API limits or dependencies cause runs to take time, adjust the wait time with -lock-timeout.

  • Verify the environment with terraform workspace show before running
  • Make differences explicit via environment variables and tfvars, and review through commit management
  • Prevent concurrent destruction with remote backend plus locking
  • Curb misuse of -auto-approve with approval-gated pipelines

Combining workspaces and variables

terraform workspace list
terraform workspace select prod
terraform plan -destroy -var-file=env/prod.tfvars -lock-timeout=5m -out=tfplan
terraform destroy -var-file=env/prod.tfvars

Handling Failures: Dependencies, Drift, and Rate Limits

Dependency errors stem from upstream resources still remaining, circular references, or provider limits. Break the plan down to destroy dependents first, or disconnect them safely by hand and then re-run. Use -target minimally and only for this staged tear-down.

Drift (divergence between state and reality) comes from external changes or past state operations. First visualize the diff with plan; if needed, restore consistency with import before running destroy. If you hit API rate limits, lower -parallelism to give retries some breathing room.

  • Make dependents explicit: verify depends_on and the actual relationship (e.g., attachments)
  • For drift, it is safer to recover with import before destroy
  • Lower -parallelism to avoid provider rate limits
  • state rm is not a physical deletion. Use it cautiously as a last resort

Common recovery commands

# Target the dependent resource first and delete in stages
terraform destroy -target=aws_route_table_association.app

# Resolve drift, then delete
terraform import aws_iam_role.app my-role-arn
terraform plan -destroy

# Relieve rate limiting
terraform destroy -parallelism=2

Check Your Understanding

Associate

問題 1

In a development environment, you want to safely delete only a specific Lambda function while keeping the API Gateway. Which is the most appropriate procedure?

  1. A. First confirm the plan with terraform plan -destroy -target=aws_lambda_function.fn, then run terraform destroy -target=aws_lambda_function.fn
  2. B. Run terraform state rm aws_lambda_function.fn and then do nothing
  3. C. Delete the Lambda from the AWS console and leave Terraform state alone
  4. D. Run terraform destroy to delete everything and recreate what is needed

正解: A

Partial deletion uses -target as an exception. First visualize the impact with plan -destroy -target, confirm there are no issues, and then run a targeted destroy. state rm does not perform a physical deletion, and manual deletion via the console causes drift. Full deletion does not meet the requirement.

Frequently Asked Questions

What scope of dependencies does -target include?

Dependencies required by the specified resource may be included in the plan, but dependents (upstream resources that depend on it) are not. So for partial deletion, you must verify that breaking the dependents temporarily is acceptable for your design.

What is the difference between terraform plan -destroy and terraform destroy?

plan -destroy only creates a deletion plan and makes no changes to your infrastructure. destroy actually applies the deletion after confirmation. For safe operations, always proceed in the order plan -destroy → review → destroy.

Can you bypass a failure caused by lifecycle.prevent_destroy?

You cannot bypass it. prevent_destroy blocks at the planning phase, so even -auto-approve or -target cannot get past it. If deletion is required, temporarily remove the setting from your code, review it, then re-plan and apply.

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.