Terraform’s prevent_destroy lifecycle argument doesn’t actually stop Terraform from destroying resources; it just makes Terraform complain loudly if you try.

Let’s see it in action. Imagine you have a critical database instance that you absolutely don’t want to accidentally delete. You’d add prevent_destroy to its resource block:

resource "aws_db_instance" "critical_db" {
  identifier           = "my-critical-database"
  instance_class       = "db.t3.micro"
  allocated_storage    = 20
  engine               = "postgres"
  engine_version       = "13.7"
  username             = "admin"
  password             = "supersecretpassword"
  skip_final_snapshot  = true
  # ... other AWS-specific configurations

  lifecycle {
    prevent_destroy = true
  }
}

Now, if you run terraform destroy or try to terraform apply a configuration that removes this resource, Terraform will halt execution and show you an error.

$ terraform destroy

Terraform used the selected backend "s3"
Terraform has been built with Go 1.19.4
...

Error: Cannot destroy instance (arn:aws:rds:us-east-1:123456789012:db:my-critical-database)

The Terraform configuration intentionally includes a resource
that is configured to prevent its own destruction. This is to
ensure that critical infrastructure is not accidentally removed.

If you are absolutely certain that you want to destroy this resource,
you must explicitly remove the `prevent_destroy = true` lifecycle
argument from the configuration and run Terraform again.

The problem prevent_destroy solves is accidental deletion of vital infrastructure. It acts as a safety net, forcing you to acknowledge and explicitly opt-in to destroying a resource that has been marked as too important to remove casually. This is crucial in production environments where deleting a database, a load balancer, or a critical compute instance can have immediate and severe consequences.

Internally, prevent_destroy is a flag within Terraform’s resource lifecycle management. When Terraform plans an operation, it evaluates the lifecycle block for each resource. If a prevent_destroy = true is found and the planned operation is a destruction, Terraform injects an error into the plan, preventing it from proceeding. It’s not a permission system or an external guardrail; it’s a built-in check within the Terraform execution engine itself.

The main lever you control is the prevent_destroy boolean value within the lifecycle block. Setting it to true enables the protection. To allow destruction, you must change it to false or remove the lifecycle block entirely.

The one thing most people don’t realize is that prevent_destroy is evaluated after Terraform has already decided to destroy the resource as part of the plan. It’s not a filter on what can be destroyed, but a final warning before it will be destroyed. This means you can’t use it to prevent a resource from being targeted for destruction in the plan; you can only prevent the destruction from happening if you try to execute that plan.

The next concept you’ll encounter is managing multiple environments with Terraform, particularly how to handle sensitive configurations like prevent_destroy across development, staging, and production.

Want structured learning?

Take the full Terraform course →