linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
Intro
Lessons
Footer
linuxlab-TutorialsPricingAboutPrivacy & cookies
Copyright © 2026 LinuxLab. All rights reserved.
linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
  • Introduction
  • Lessons
  • How it works
  • Knowledge base
  • Cheat sheet
  • Capstone
  • Interview prep
home/terraform/lessons/tf-beginner-06-destroy

lesson ── terraform-beginner ── ~8 мин ── 3 шагов

Destroy: tear down infrastructure safely

Destroy is apply with a minus sign. Terraform looks at the state, sees every resource it once created, and deletes them through the cloud API. You use it for ephemeral environments (spin up, check, tear down) and for closing out projects.

In real work destroy is dangerous: the data is gone, there is no undo. That is why there is prevent_destroy, a guard against accidents. See tf-destroy and tf-resource-lifecycle.

▶ интерактивный sandbox

Поднимется пара контейнеров: terraform 1.9 и localstack 3.8 в одной сети. В браузере откроется терминал, можно сразу terraform init. Каждый шаг проверяется автоматически. TTL 45 минут, без регистрации.

запустить sandbox →

stack ── terraform · localstack · 1 GB RAM · самоуничтожается через 45 мин простоя

Шаги

  1. 01

    Create a bucket that you will tear down later

    hcl
    resource "aws_s3_bucket" "demo" {
      bucket = "linuxlab-destroy-${random_id.suffix.hex}"
      tags = {
        Owner = "student"
      }
    }
    resource "random_id" "suffix" {
      byte_length = 4
    }
    bash
    cd /home/student/tf-destroy
    terraform init -input=false
    terraform apply -auto-approve -input=false

    The state will hold one resource (plus the random_id).

    подсказка

    If apply fails: check the LocalStack logs with `docker logs localstack`.

    ✓ Bucket created. Now we will try destroy with protection.

  2. 02

    Add prevent_destroy and try to tear it down

    Add a lifecycle block to the bucket:

    hcl
    resource "aws_s3_bucket" "demo" {
      bucket = "linuxlab-destroy-${random_id.suffix.hex}"
      tags = {
        Owner = "student"
      }
      lifecycle {
        prevent_destroy = true
      }
    }

    Apply so that lifecycle lands in the state:

    bash
    terraform apply -auto-approve

    Now try to tear it down:

    bash
    terraform destroy -auto-approve

    It should fail with an error:

    Error: Instance cannot be destroyed
    Resource aws_s3_bucket.demo has lifecycle.prevent_destroy set,
    but the plan calls for this resource to be destroyed.

    This is protection, not a bug. In production it saves you from a typo in git rm.

    подсказка

    If destroy went through: prevent_destroy did not take effect. Run `apply` again and check that the HCL was saved.

    ✓ Protection works: destroy is blocked. To tear it down, you first have to remove prevent_destroy.

    The same thing on OpenTofu

    OpenTofu keeps its CLI and state compatible with Terraform for the commands in this step: migration usually goes through mv .terraform .terraform.bak; tofu init -upgrade. But on the first switch, back up the state and run on a feature branch. The differences cluster in the newer features (variables in backend, state encryption, OCI registry-backed modules). See tf-opentofu-parity for the full matrix.

    • → OpenTofu parity
  3. 03

    Remove the protection and tear it down

    To actually tear down the bucket, you first have to remove prevent_destroy. Delete the lifecycle block from main.tf (or change it to prevent_destroy = false). The file should look like this again:

    hcl
    resource "aws_s3_bucket" "demo" {
      bucket = "linuxlab-destroy-${random_id.suffix.hex}"
      tags = {
        Owner = "student"
      }
    }
    resource "random_id" "suffix" {
      byte_length = 4
    }

    Apply (lifecycle is removed from the state):

    bash
    terraform apply -auto-approve

    Now destroy works:

    bash
    terraform destroy -auto-approve

    At the end you will see:

    Destroy complete! Resources: 2 destroyed.
    подсказка

    If destroy still fails: prevent_destroy is still in the HCL. Delete the lifecycle block entirely or set it to false.

    ✓ All resources torn down. State is empty. This is the right path: a two-step guard.

    What happens if you lose the state

    If the terraform.tfstate file is lost (deleted, never committed, the disk died): as far as Terraform is concerned, the created resources no longer exist. You can no longer tear them down with destroy (there is nothing to tear down). You can: (a) import them back with terraform import (slow, one resource at a time); (b) delete them by hand through the AWS Console or CLI. This is why remote state with encryption and backups is a necessity in production, not a luxury.

    • → Terraform state
    • → Backend for state

Что ты узнал

You saw destroy in action, then tried to protect a resource with prevent_destroy = true and confirmed that Terraform really blocks the deletion. This is your safety net in production.

команды

  • terraform destroy -auto-approvetear down every resource in state
  • terraform plan -destroyshow what would be torn down, without confirming
  • terraform apply -auto-approve -replace=<address>recreate one specific resource

концепции

  • · Destroy = delete everything in state, in reverse dependency order
  • · prevent_destroy blocks a deletion: it never gets past the plan
  • · After destroy the state file stays, but its resources are empty

← предыдущий

Infracost, estimating the cost of a plan

следующий →

Remote state in S3 (on LocalStack)

Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies