Terraform Destroy Command: A Guide to Controlled Infrastructure Removal
Tags: terraform, devops, cloudcomputing, cloudskills
Published: 2024-05-27 12:57:30

In this guide, we explore the essential elements of `terraform destroy`, unraveling why this command is a fundamental part of the Terraform workflow. Additionally, we will cover best practices and considerations to ensure the effective and safe execution of `terraform destroy` within your infrastructure management processes.

‍**What is terraform destroy**
------------------------------

Among the suite of [Terraform commands](https://www.env0.com/blog/what-is-terraform-cli), `terraform destroy` holds a crucial role in infrastructure management. This command is specifically used to remove the infrastructure that has been provisioned using Terraform Infrastructure-as-Code (IaC) configuration. 

When `terraform destroy` is executed, Terraform reviews the state file to identify and systematically remove managed infrastructure from your cloud environment (AWS, Azure, GCP, etc.). 

While each of the commands in the Terraform workflow (`terraform init`->`terraform plan`->`terraform apply`), contributes to creating a new infrastructure, `terraform destroy` command is explicitly used to delete all (or some targeted) infrastructure defined in your Terraform IaC. 

Unlike `terraform apply`, which brings resources up to date with the desired state, `terraform destroy` command does the opposite by ensuring that all (or some) of the resources managed by Terraform are deleted.  

Before we dive in deeper, for additional context, here is a short description of Terraform commands and their functions:

*   [**`terraform init`**](https://www.env0.com/blog/terraform-init)**:** Used to initialize a working directory containing Terraform config files and to download providers and modules.
*   **`terraform validate`:** Validates the Terraform config in that particular directory to ensure they are syntactically valid and internally consistent.
*   [**`terraform plan`**](https://www.env0.com/blog/terraform-plan): Creates an execution plan. Using this command prompts Terraform to perform a refresh and determine the actions necessary to achieve the desired state in specified config files.
*   [**`terraform apply`**](https://search.google.com/u/0/search-console/performance/search-analytics?utm_source=gws&utm_medium=onebox&utm_campaign=san&resource_id=sc-domain%3Aenv0.com&num_of_days=7&query=!terraform%20apply&breakdown=page&metrics=POSITION&page=!https%3A%2F%2Fwww.env0.com%2Fblog%2Fterraform-apply-guide-command-options-and-examples)**:** Used to apply the changes required to reach the desired configuration state. By default, the `apply` command scans the current directory for the config and applies the changes appropriately.

**How does terraform destroy Command Works?**
---------------------------------------------

To demonstrate how the command works, let us take an example to help us understand _terraform destroy_ more clearly. 

For that, we’ll spin up two EC2 instances, review the entire Terraform workflow, and assess the aftermath of _terraform destroy_.

    #main.tf
    provider "aws" {
      region = "us-west-1"
    }
    variable "instances" {
      default = {
        "env0-instance-az1 = "us-west-1b",
        "env0-instance-az2" = "us-west-1c"
      }
    }
    resource "aws_instance" "tf_instances" {
      for_each = var.instances
      ami           = "ami-0ce2cb35386fc22e9"
      instance_type = "t2.micro"
      availability_zone = each.value
      tags = {
        Name = each.key
      }
    }

### **Terraform Workflow to Create Infrastructure**

By running the Terraform workflow (`terraform init`-> `terraform plan`-> `terraform apply`), we were able to create **env0-instance-az1** and **env0-instance-az2** instances. They’re deployed in their respective availability zones.

![Terraform Workflow to Create Infrastructure](https://assets-global.website-files.com/63eb9bf7fa9e2724829607c1/6602b3e554bd05cf0f420052_tNYDZof4YFTBvaSL8zC3OxZp0LT39RjmzHF6YAP9j6xDEGr8k_UUbryhGs_5fBqkYbH6tCwG1d95wZocBU6ERmQcgVOaINdAqAknpblU562ZujKiNXkdKlIbxFPm-qTpEqxZnwM9cD852R5v_8Z2kK4.png)

Let us inspect the state file (**terraform.tfstate**) now, to check the metadata of our provisioned infrastructure (**env0-instance-az1** and **env0-instance-az2**). We can see the information of both our instances in the state file.

![check the metadata of our provisioned infrastructure ](https://assets-global.website-files.com/63eb9bf7fa9e2724829607c1/6602b3e56da9e63e10e2fadd_ZPy1f-KtTrh2CXqTGmDWWUU7YsdOCJVnuLXHmqh1Rwol2vsJFtDDXpJDTypHOZ2A7D8W_Cf3__1_YzYUN3YBpLWaRLyjIuUsZL_h_u5lvRYwTxXYEqfi_BcixAMXNDAiDxwR2XZdtbUsToSzzuELU0o.png)

![](https://assets-global.website-files.com/63eb9bf7fa9e2724829607c1/6602b3e579ec850c12dd07f8_b9a9dYhr-JFe_CAYPX3CzhINOmW1-ztQEwzNW549RGheh6Pw73t2DdIFoM5mlkK0Q-LUxIknVoXFB7iVSEgmstTTUceTG2lOPENnBmtdy8Rj-a7KE9P0BtHl5CYssphA6XHIpMs-sjkD8-J0bBvfrPQ.png)

### **Executing terraform destroy Command**

After running `terraform destroy`, we can observe that our state refreshes and Terraform outputs the resources that will be destroyed from our cloud environment.

![observe that our state refreshes and Terraform outputs ](https://assets-global.website-files.com/63eb9bf7fa9e2724829607c1/6602b3e5ef7bc57779d8f4ec_G3y6HWniTk_UeMYCOMUaBQTiJBdkuYULGFAFHP6s6qU0N9VLz35EB7668C7RmXNbx6LP2Bvh0W3mPHJK4pZv10ncUZuPsTraC4kPM0s7ku-jL9JW2QPtQwU2byxZTWMK2lVYGMdq_co0BbMuUxXpBQk.png)

![](https://assets-global.website-files.com/63eb9bf7fa9e2724829607c1/6602b3e50990b121245e7d8f_gqq_FMjEyo0_Tl1i-ViP44xgU1W0133_m9WRpujRqOqQwpRNBLdHOQu_CrrZXN_X0udMmaQbTCmqWkraABTletyPZsrY4rkcx2pc8BNJIQw-ziq8RDZJ8Ptz5SzssUI6IirUquQ3T4pEXus-MZy3z58.png)

Like `terraform apply`, we are prompted to confirm these changes that will be made to our infrastructure. Confirm with a ‘yes’ to `destroy` the resources.

![we are prompted to confirm these changes that will be made to our infrastructure](https://assets-global.website-files.com/63eb9bf7fa9e2724829607c1/6602b3e5443ea2b476a0c540_19ZzarulLUwON_Honle5ZW5AwCVihGRgQBguff7duk--1am1iuKDsiy-aMDi0UZ3fw5eosXtplG2tgN0ySZzpam4d-hg4Wisw6ZV00oMoiLXotBptlZmfxa7ix_YsAbrRZDZItKgIMwaOnhQMSVMjjk.png)

After the resources are deleted, Terraform updates our state (**terraform.tfstate**) file to reflect that these resources no longer exist.

![Terraform updates our state](https://assets-global.website-files.com/63eb9bf7fa9e2724829607c1/6602b3e5f224f5ff2d3babb8__YUVb_vnTMwl3Pu4FnZFEdE223Lc2B-i1rOuDMPTYsKeWcTeDf5R2y3EadVyOluPN5cCur7MOErtnE5otuMEcT1PVPZaxek4NgJb7u77oEbj_QiFPjgS0or20BqM4y0sBmnQqHuE6a7y7kFZp12xGa4.png)

**When, Why and How to use terraform destroy?**
-----------------------------------------------

Here are some scenarios when and why you might use `terraform destroy`:

*   **Cost Management:** If you're running resources that are no longer needed or are underutilized, using `terraform destroy` can delete those resources and help reduce costs by ensuring you're not paying for what you don't use.
*   **Security Purposes:** In cases where threat actors might have compromised your infrastructure or if you need to ensure that all resources are in a known secure state, destroying and re-provisioning can be an effective strategy.
*   **Resource Reallocation:** In scenarios where infrastructure needs to be re-architected or reallocated for different projects or priorities, destroying the current setup might be necessary before reallocating those resources.

**Using terraform destroy Options**
-----------------------------------

Let us look at how we would use `terraform destroy` command with various options.

### 1. **Terraform destroy -auto-approve**

The `-auto-approve` flag always skips the interactive approval for confirming the changes for your infrastructure. In the case of `terraform destroy`, it bypasses the approval step, and Terraform proceeds to destroy your infrastructure.

In automated environments such as CI/CD pipelines, where human interaction is not possible, the `-auto-approve` flag ensures that the destroy operation can proceed without manual intervention.

![Terraform destroy -auto-approve](https://assets-global.website-files.com/63eb9bf7fa9e2724829607c1/6602b3e5ccf17d314b8e23ab_vK87wwUIFtwZMPpciKspQfvDdh9gjcPmebF0mcwN1SrAEkQ0UUcKAos-o04q5JD-27m4FaTX0_tNp5C4AD-xgdeMTsZHRB_-VCARuqodHOvjLdkwN0CUiAnRqRr5gBgrTUOSpEtxZTNFe495VP3Kb_k.png)

![](https://assets-global.website-files.com/63eb9bf7fa9e2724829607c1/6602b3e5eee2904b87b9c9a7_gl52IE_V9l_cdBCWqRbtFA5R-KCaeEyD839elCceBcwlk4A_IgA8FQtnF1vda_0ijKP618ev4JUdcYrcouf21rmvax7OijIiRuappeNZHb28bC3jRXJeEAbzgVfwHjTaIGzHbvy-SwduQitQ27D4Od0.png)

### **2. Terraform destroy -target** 

The `terraform destroy -target=resource_type.resource_name` option should be used with caution and in specific scenarios where you need to remove an individual resource or a set of resources, without impacting the entire infrastructure managed by Terraform.

![Terraform destroy -target ](https://assets-global.website-files.com/63eb9bf7fa9e2724829607c1/6602b3e5339595149f4b8994_HZxqZowddipFvZgHirqGYE2LZwnfW4RiKWc2IdOdPEJBFLu04VLojeQRJ6dW3iP8STv7grbrs8DGdymAL1bLkpekpfIcRWSI4BOBaeoe8dDkuzJaW5gL-sKvK-kpwPWOWCspT4ZXkRiHTQG1AsFFo38.png)

### **3. Terraform destroy -refresh=false**

The `-refresh` option in the `terraform destroy` command can be used to control whether Terraform should refresh the state before performing the `terraform destroy`.

For instance, in a large infrastructure environment, you can use `-refresh=false` option when the refresh process is time-consuming since Terraform checks the status of each resource in the cloud provider. 

This flag skips the state file refresh and speeds up the `destroy` process.

![Terraform destroy -refresh=false](https://assets-global.website-files.com/63eb9bf7fa9e2724829607c1/6602b3e5d2034ce8c388424e_GfRw3jyUoWkDX-fPd3VWNb6zeeD9xw5xxZS8zvnzCBRSbkIhkVH0o5VHndAPK9P1llFVaRu-FpFBT6foMg42tfJPJR6SEPxow32A-IFgABZIgcpDay2UXVPfLXXt_oWugG3SmxgZwo-iINxY8hArlRY.png)

### **4. Terraform destroy -lock and -lock-timeout**

The `terraform destroy -lock` flag is used to control Terraform's state-locking mechanism during the `destroy` operation.

Using the `-lock=true` can be beneficial when you are working in a team environment where multiple operations in the same state might occur simultaneously. 

This ensures that no other operations interfere with the `destroy` process, maintaining state consistency and preventing potential conflicts.

The `-lock-timeout` flag can be used to extend the waiting period for a state lock. For example, `terraform destroy -lock-timeout=20s` locks the state file for 20 seconds.

![Terraform destroy -lock and -lock-timeout](https://assets-global.website-files.com/63eb9bf7fa9e2724829607c1/6602b3e51c648453424d0932_renLZb-E4BwvFQxrqIcRbDe236_J25PO397dTT8ajotgwaIrVq7QCZi2IhNU9IHGNq8Q2nBheUGJUJD9P53a011KiD0H_pGl2osbkynB1XiX8ieEB__MKhMFhkukQkyNHkheTAg7lDW6FZ_h5SSSLnc.png)

‍**Best Practices**
-------------------

The `destroy` command is irreversible, and running it carelessly might cause important infrastructure to disappear forever from your environment. 

Before discussing best practices, it is important to note that terraform destroy can be run locally and in automated CI/CD pipelines. The `terraform destroy` command is typically used locally for dev or test environments to swiftly destroy resources, while in CI/CD pipelines, it's recommended for staging and production to ensure controlled, team-reviewed resource destruction.

Let us look at the best practices that must be followed when dealing with `terraform destroy`.

### **1. Regular Backup of State Files and Sensitive Data**

Regularly backing up state files (**terraform.tfstate**), including the automatically generated **terraform.tfstate.backup**, is essential.

Terraform creates the **.backup** file before it writes to the main **terraform.tfstate** file, serving as an immediate previous version of your state. This can be invaluable in case of accidental corruption or deletion of the **terraform.tfstate** file.

When planning backups, ensure both the current state file and the **.backup** file are included.

For enhanced disaster recovery, consider replicating state files in remote backends (like S3) to other regions. Additionally, sensitive data or secrets (such as cloud provider API keys, SSH keys, database credentials, etc.) managed by Terraform should also be securely backed up and encrypted to prevent unauthorized access.

### 2. **Using Workspaces for Environment Isolation**

Manage separate state files for different environments (such as development, staging, and production) under the same configuration using Terraform workspaces. 

Utilizing workspaces for environment isolation is a best practice that can significantly reduce the risk of impacting the wrong environment when performing destructive operations like `terraform destroy`. 

Before executing the `destroy` command, always confirm you are in the correct workspace to ensure that only the intended environment is affected. 

### 3. **Implement a Review Process for Infrastructure**

Implementing a comprehensive review process by incorporating a gated check-in process in CI/CD pipelines adds an additional layer of security and accountability.

This process should include:

*   **Code Review:** Changes to Terraform configurations, especially those leading to resource destruction, should be reviewed by multiple team members.

*   **Impact Analysis:** Automatically run `terraform plan -destroy` to show what resources will be affected without making any changes. Document and review infrastructure changes.

*   **Environment-specific gates:** Enforce stricter reviews and require additional checks or tests that mimic the production environment for the staging environment. For production, implement the highest level of scrutiny by senior infrastructure engineers and double-check automated tests.

*   **Audit Trails:** Ensure that all actions and approvals related to the Terraform changes are logged and accessible for audit purposes.

**What Happens when terraform destroy Fails?**
----------------------------------------------

When `terraform destroy` fails, it can lead to several issues:

### **1. Partial Resource Deletion**

This can occur if Terraform encounters an error while attempting to `destroy` one or more resources. The error could be due to permissions issues, dependencies between resources that Terraform is not aware of, or external factors such as network timeouts.

‍**Mitigation:**

*   **Resolve dependencies:** Manually review and ensure all dependencies are correctly reflected in your Terraform configurations. Use `-target` flag to `destroy` specific resources.
*   **Check Permissions:** Verify that you have sufficient RBAC permissions to delete Terraform resources, in case you're using Terraform Cloud or other platforms.
*   **Network Timeouts:** In case of network timeouts, re-running the `terraform destroy` command with a stable network may resolve the problem.

### ‍**2. Inconsistent State**

The Terraform state file may become inconsistent with the actual infrastructure if manual changes were made outside Terraform, or if previous Terraform operations were interrupted.

‍**Mitigation:**

*   **Refresh State:** Run `terraform refresh` to update the local state file with the actual state of resources in the cloud.
*   **Manual State Edit:** If refreshing the state does not resolve the inconsistencies, manually edit the state file using the `terraform state rm` command to remove the problematic resources from the state file.

### **3.State Locking Issues**

Terraform state locking prevents multiple simultaneous operations from corrupting the state. If a previous operation didn't complete properly, the state may remain locked, blocking further operations.

‍**Mitigation:**‍

*   **Investigate Lock:** Use the `-lock-timeout` option to wait for a lock to be released before or use terraform force-unlock with the lock ID, ensuring no other operations are currently running.
*   **Manual Unlock:** As a last resort, manually unlock the state through the backend (like S3, Azure Blob Storage, etc.) if the automatic unlock fails.

env0: Scheduling, TTL, Destroy Protection and more
--------------------------------------------------

‍[Time to Live](https://docs.env0.com/docs/policy-ttl) (TTL) is one of the functionalities [env0](https://www.env0.com/)'s offers, which uses `destroy` to streamline environment lifecycle management. 

Configuring TTL provides users with the ability to easily set predefined timers, dictating the lifespan of their environments, which helps optimize resource allocation and avoid cost sprawl. 

Additionally, [env0](https://www.env0.com/) also allows you to set Organizational- and Project-level TTL. These can be used to provide helpful guardrails, standardize IaC usage, and grant autonomy to teams new to Infrastructure-as-Code, without the risk of things going south.  
  
![](https://assets-global.website-files.com/63eb9bf7fa9e2724829607c1/6602b3e5d14ae9c8de1d5ccd_TRmZxLh1X3eC9bYHYgmD94vv1ekE9lEWEwpsWC70x2GwSGvyx492QdukE-LuV0BGd2uf4CjdezGY-u0L9sV_O81-GvOug738vsdT_nX86gnxym1uNPYXGWIDUfGeNuzuAEwmv_2Xipm3YJqAXPOUNiM.png)

Moreover, env0’s [Scheduling](https://docs.env0.com/docs/scheduling) functionality aids a layer of automation, triggering of infrastructure deployments and destructions on a predefined schedule, defined by cron expressions. 

![](https://assets-global.website-files.com/63eb9bf7fa9e2724829607c1/6602b3e5cd0a02b23d66d6d3_-fEzE9VBvNbAmzuRCKQXfrfQ1Rd8asXJI8btfsScQ7VR-KwagIt-9RZxT8hXoKAh7vDxBREjKIc6VR10ZBOou0vX1qwjTgy2OO5o2rPDw8zxSnP0A3etgY_CfAJM92ePeARF4gjzsaKC0ErY_zBiCrw.png)

To avoid accidental deletion, env0 also comes with a [Destroy Protection](https://docs.env0.com/docs/destroy-protection) option. When enabled, it restricts functionalities such as the _‘_Destroy_’_ button, ‘Time Left’ indication, and the ‘TTL panel’ to be applied to the protected environment.

![](https://assets-global.website-files.com/63eb9bf7fa9e2724829607c1/6602b3e64f1844efa7a1a8df_0VpK_AOKUAnkH16YpFFG9s8sWZIvIXSKmN8o_yvFKoCr99ojs3jI0_k7jFH7yN1KornAXsp0E4XfI8D65h7U55hSQbJRz50VsoQPC-9fME49amsILH4cWtH6a21E5AbMeHrSgAJlBUItnqDWg5kdxo0.png)

Lastly, the [Skip State Refresh](https://docs.env0.com/docs/skip-state-refresh) feature in env0 allows users to bypass state mismatches during the destruction phase of an environment. 

This is a last-resort option equivalent to the Terraform command, `terraform plan -refresh=false`, ensuring that the environment can still be destroyed even when state mismatches occur, such as inaccessible secrets or data sources.

![](https://assets-global.website-files.com/63eb9bf7fa9e2724829607c1/6602b3e5ce0674dd007ac13a_lULCazWECV2n4oPP_cpnZIabxID2LorAWHV6I55j62PWr-b0S7mwlaK9LyaOpNOYXJeDxKFKhmp_rQTeXDpQKGmfo693BMPpKyFEkylxhiNeuauQ3Cbsj3NuFL_Q4hGLzRS4ehcNorQlDjrkh_L7zkA.png)

Frequently Asked Questions
--------------------------

### **Q. What is the difference between terraform destroy and state rm?**

To answer this question, here is a short comparison table:

![comparison table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/grl8ejq3oo1o4bdnnjnd.png)

### **Q. Is Terraform destroy reversible?**

No. Once executed, `terraform destroy` is not reversible. It permanently deletes resources from the cloud.

### **Q. How can I prevent accidental execution of terraform destroy?**

It's recommended to use Terraform state locking. Another alternative is to use the `prevent_destroy` lifecycle meta-argument. When prevent\_destroy is set to true, Terraform will generate an error if the `destroy` operation tries to destroy the resources, acting as a safeguard against accidental deletion.

### **Q. Does terraform destroy delete manually created resources?**

No. The `terraform destroy` command just deletes the resources that are under Terraform’s management and control.

### **Q. Can I preview what terraform destroy will do before executing it?**

Yes, you can execute `terraform plan -destroy` for a preview of the actions Terraform will take, allowing you to verify that only the intended resources are targeted for deletion.