Skip to content
Infrastructure as Code iac workflow 4 min read

terraform destroy

terraform destroy removes every resource that Terraform currently manages in a workspace, deleting cloud infrastructure in the correct dependency order. It is the inverse of terraform apply: instead of reconciling state toward your configuration, it reconciles state toward empty. Because it is irreversible for most resources, destroy is the command you reach for when tearing down ephemeral environments, cleaning up after a CI run, or decommissioning a stack — and the one you must guard most carefully in production.

How destroy works

When you run terraform destroy, Terraform builds a destroy plan. It reads the current state, walks the resource dependency graph in reverse (children before parents), and proposes a deletion for every managed resource. The plan is shown for review and, by default, requires interactive approval before anything is deleted.

terraform destroy

Output:

aws_instance.web: Refreshing state... [id=i-0a1b2c3d4e5f6a7b8]
aws_security_group.web: Refreshing state... [id=sg-0123456789abcdef0]

Terraform will perform the following actions:

  # aws_instance.web will be destroyed
  - resource "aws_instance" "web" {
      - ami           = "ami-0c7217cdde317cfec" -> null
      - instance_type = "t3.micro"               -> null
      - id            = "i-0a1b2c3d4e5f6a7b8"    -> null
    }

  # aws_security_group.web will be destroyed
  - resource "aws_security_group" "web" {
      - id   = "sg-0123456789abcdef0" -> null
      - name = "web-sg"               -> null
    }

Plan: 0 to add, 0 to change, 2 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value:

Resources are deleted in reverse dependency order so that, for example, the EC2 instance is removed before the security group it references. Typing yes executes the deletions; anything else aborts. To skip the prompt in automation, pass -auto-approve — but only where a human has already reviewed the plan or the workspace is genuinely disposable.

terraform destroy -auto-approve

Warning: terraform destroy deletes real infrastructure and there is no undo. Always read the plan, confirm you are pointed at the right workspace (terraform workspace show), and never wire -auto-approve into a pipeline that can touch production.

terraform destroy is fully supported by OpenTofu (tofu destroy) with identical semantics and flags.

Previewing a destroy plan

You can generate and save a destroy plan without executing it by combining terraform plan with the -destroy flag. This is useful in code review or change-management workflows where the teardown must be approved before it runs.

terraform plan -destroy -out=teardown.tfplan
terraform apply teardown.tfplan

Saving the plan to a file guarantees that the exact set of deletions you reviewed is what gets applied, even if state drifts in between.

Targeting a subset of resources

To destroy only specific resources rather than the entire workspace, use -target. The address can be a single resource, a module, or an indexed instance. Terraform still respects dependencies, so anything that depends on the target is destroyed too.

terraform destroy -target=aws_instance.web
terraform destroy -target='module.cache' -target='aws_s3_bucket.tmp[0]'

Tip: -target is an escape hatch for exceptional situations, not a routine workflow. It can leave state inconsistent with configuration because Terraform skips the normal full-graph reconciliation. Prefer refactoring your configuration (for example, removing a count instance) and running a normal destroy.

Guarding resources with prevent_destroy

The prevent_destroy lifecycle argument is a hard safety net. When set, any plan that would delete the resource — whether from terraform destroy, a -target, or a config change — fails immediately with an error instead of proceeding.

resource "aws_s3_bucket" "logs" {
  bucket = "acme-prod-audit-logs"

  lifecycle {
    prevent_destroy = true
  }
}

Output:

Error: Instance cannot be destroyed

  on main.tf line 1:
   1: resource "aws_s3_bucket" "logs" {

Resource aws_s3_bucket.logs has lifecycle.prevent_destroy set, but the plan
calls for this resource to be destroyed.

To actually destroy a guarded resource you must first remove or comment out the prevent_destroy block, then plan again. This deliberate two-step protects stateful resources like databases, S3 buckets, and KMS keys from accidental deletion.

Safe teardown of ephemeral environments

Destroy shines for short-lived environments — per-pull-request preview stacks, integration test fixtures, and demo sandboxes. Use a dedicated workspace per environment so a teardown can never touch another environment’s state.

terraform workspace select pr-1423
terraform destroy -auto-approve -var-file=envs/preview.tfvars
terraform workspace delete pr-1423

A typical CI teardown job runs in the workspace’s own remote backend, applies a strict input file, and tears everything down once the PR merges or closes. Because the workspace is isolated, -auto-approve is acceptable here.

Common destroy flags

FlagPurpose
-auto-approveSkip the interactive confirmation prompt
-target=ADDRRestrict the destroy to a resource, module, or instance (repeatable)
-var-file=FILESupply input variables needed to resolve the configuration
-refresh=falseSkip refreshing state before planning the destroy
-lock-timeout=DURATIONWait for a held state lock instead of failing immediately
-parallelism=NLimit concurrent destroy operations (default 10)

Best Practices

  • Always review the destroy plan and confirm terraform workspace show before approving — there is no undo.
  • Reserve -auto-approve for genuinely disposable, isolated workspaces such as CI preview environments.
  • Put prevent_destroy = true on stateful, high-value resources (databases, log buckets, KMS keys) so accidental deletes fail loudly.
  • Use -target only as an exception; prefer refactoring configuration and running a full destroy to keep state consistent.
  • Isolate each ephemeral environment in its own workspace and backend so a teardown can never affect another stack.
  • For change-controlled teardowns, save the plan with terraform plan -destroy -out=... and apply the exact reviewed file.
Last updated June 14, 2026
Was this helpful?