How to stop terraform destroy from wiping production
Add a lifecycle block with prevent_destroy = true to the resource. Terraform then rejects any plan or apply that would destroy it, including a full terraform destroy, and returns an error instead. That’s the direct answer. The catch is that it only protects you inside Terraform, and there are at least three ways production gets wiped anyway.
What prevent_destroy actually does
It’s a setting inside the resource’s lifecycle block, and it’s worth turning on for anything you’d panic about losing.
resource "aws_db_instance" "production" {
identifier = "myapp-production"
engine = "postgres"
instance_class = "db.r6g.large"
lifecycle {
prevent_destroy = true
}
}
With that in place, Terraform will fail the plan if any change would destroy the database, and it will refuse a terraform destroy outright. It’s a good safety lock on production databases, state buckets, and core networking. Set it. Just don’t mistake it for a wall.
Why prevent_destroy isn’t enough
The rule only works while Terraform is the one doing the deleting. There are three common ways around it.
Remove the block and it’s gone. prevent_destroy only protects a resource while the lifecycle rule is in the config. Delete the resource’s block and Terraform destroys it on the next apply like any other change. Delete just the rule, and nothing is destroyed yet, but the lock is off and the next terraform destroy goes through. A rushed pull request that removes a module can do this without anyone noticing.
Edit the state and it’s gone. Run terraform state rm on the resource, and Terraform forgets it exists. The lifecycle rule went with it. Now the resource can be deleted with nothing to stop it.
Skip Terraform entirely and it’s gone. This is the big one. prevent_destroy has no idea what happens in the AWS console, the CLI, or an SDK call. Someone with delete permissions clicks the button, and Terraform finds out on the next plan, when it reports drift against a resource that no longer exists.
How do I stop terraform destroy in CI?
Keep prevent_destroy on the critical resources, and separately control what your pipeline is allowed to do. A CI job usually runs with broad cloud credentials, which means it can delete resources outside Terraform regardless of any lifecycle rule. The rule guards the plan. The credentials guard the account, and they’re the part people forget.
That’s the same lesson as handing out cloud access that expires on its own instead of leaving a standing key in a CI config where it waits to be misused.
What actually protects production
Line the three bypasses up and the pattern is clear. prevent_destroy protects the Terraform workflow. It does nothing about a person or a process with permission to delete the actual resource, and that’s where most real incidents come from. This is the same gap the native cloud controls have, which we covered in preventing accidental deletion across AWS, Azure, and GCP.
Two things close it. First, keep backups, snapshots, and versioning on, because that’s how you recover when something does get destroyed. Terraform can’t undo a destroy, so recovery has to come from somewhere else.
Second, watch the actions themselves rather than trusting a config flag to hold. Korvalis installs inside your own cloud account, reads what a live session or automation is actually doing, and cuts off a destructive one before it finishes, whether the delete comes from the console, the CLI, a CI job, a stolen key, or an AI agent. It watches the account, not just the Terraform plan, which is the layer prevent_destroy can’t reach.
Frequently asked questions
Does prevent_destroy stop console deletion? No. It only works inside Terraform. A deletion from the console, CLI, or a state edit never touches the lifecycle rule.
Can you undo a terraform destroy? Not through Terraform. Recovery depends on backups, snapshots, or versioning that existed before the destroy ran.
How do I protect a resource in CI? Keep prevent_destroy on critical resources and restrict what the pipeline’s credentials can delete, since a CI job can act outside Terraform.
If a delete that bypasses Terraform is the thing you worry about, see how Korvalis catches it or join the waitlist.