Going to AWS Summit London? 🇬🇧🇬🇧

Meet us there →

Terraform

Destroy Command – How to Destroy Resources from Terraform

Destroy resources terraform

Terraform at Scale

Manage your infrastructure as it grows with a flexible, robust workflow, drift detection and reconciliation, and policies for security and compliance.

Book a demo

Cloud resources created using Terraform are maintained using Infrastructure as Code. Any changes, commissioning, and decommissioning of resources are supposed to be handled using IaC. Teams who have adapted Terraform for infrastructure management usually have strict compliance with manual changes via the web console.

In this post, you will learn how to manage the destruction of cloud infrastructure resources that are under Terraform management (resources that are created using Terraform IaC) and how to overcome some common pitfalls.

What is Terraform Destroy?

The Terraform destroy command is a command that terminates resources managed by your current Terraform project by deleting infrastructure resources present in the state file. When the destroy command is executed, Terraform first validates the information contained in the state file by cross-checking with cloud provider APIs. Internally it builds a dependency graph to identify the sequence in which the resources are to be destroyed.

Clearly, the state file is a source of truth for Terraform to perform any operation. If the state file is corrupted then Terraform can behave in unwarranted ways. If the state file has no mention of a certain resource – but the resource exists in the real world – then running terraform destroy will NOT destroy that resource.

Note: New versions of Terraform will be placed under the BUSL license, but everything created before version 1.5.x stays open-source. OpenTofu is an open-source version of Terraform that will expand on Terraform’s existing concepts and offerings. It is a viable alternative to HashiCorp’s Terraform, being forked from Terraform version 1.5.6. OpenTofu retained all the features and functionalities that had made Terraform popular among developers while also introducing improvements and enhancements. OpenTofu works with your existing Terraform state file, so you won’t have any issues when you are migrating to it.

How to Destroy Resources from Terraform

Continuing on the importance of the state file – there are essentially two ways to destroy resources using Terraform.

1. Terraform Plan Destroy

Assuming you have a set of resources deployed using Terraform configurations, to destroy one or all of the resources in this configuration, simply remove/comment out the resource blocks and run terraform plan to validate the desired action and then apply.

During its validation phase Terraform identifies the gaps in configuration and state files. It also checks if the real-world resources exist and generates a plan to remove any resources which are available in the real world, but not in the configuration.

This also means, if we manually delete a particular resource, the next destroy cycle would take the same into consideration and only attempt to delete the resource that exists.

Running the example code below (uncommented) will create 2 EC2 instances – demo_vm_1 and demo_vm_2. To destroy one of the EC2 instances, comment out the corresponding resource block in the code – demo_vm_2.

resource "aws_instance" "demo_vm_1" {
 ami           = "ami-07df274a488ca9195"
 instance_type = "t2.micro"
 
 tags = {
   name = "Demo VM One"
 }
}
 
/*resource "aws_instance" "demo_vm_2" {
 ami                     = "ami-07df274a488ca9195"
 instance_type           = "t2.micro"
 
 tags = {
   name = "Demo VM Two"
 }
}*/

Run terraform plan and observe the output.

aws_instance.demo_vm_2: Refreshing state... [id=i-0b63433033e61d818]
aws_instance.demo_vm_1: Refreshing state... [id=i-0b46c3280f7d305df]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # aws_instance.demo_vm_2 will be destroyed
  - resource "aws_instance" "demo_vm_2" {
      - ami                                  = "ami-07df274a488ca9195" -> null
      - arn                                  = "arn:aws:ec2:eu-central-1:532199187081:instance/i-0b63433033e61d818" -> null
      - associate_public_ip_address          = true -> null
      - availability_zone                    = "eu-central-1b" -> null
.
.
.
.
}
    }

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

Terraform identifies the absence of demo_vm_2 in the configuration, but notices that it exists in the state file as well as in the real world. Thus it generates a plan to destroy that EC2 instance. Running terraform apply now would cause the destruction of this EC2 instance.

2. Terraform Destroy Command

Terraform destroy is a more common way to destroy resources managed by Terraform. The destroy command can be used to destroy a complete set of cloud infrastructure or a targeted resource.

To destroy a specific EC2 instance (demo_vm_1), the --target argument can be supplied to the destroy command with the resource path to identify the correct resource as below.

Terraform: Destroy Target

terraform destroy --target aws_instance.demo_vm_1

Terraform validates the state as well as its existence in AWS EC2 console, and triggers the deletion of the specified EC2 instance.

Terraform: Destroy Specific Resource 

.
.
.
.
- throughput            = 0 -> null
          - volume_id             = "vol-040c21ea887ddd779" -> null
          - volume_size           = 8 -> null
          - volume_type           = "gp2" -> null
        }
    }

Plan: 0 to add, 0 to change, 1 to destroy.
â•·
│ Warning: Resource targeting is in effect
│ 
│ You are creating a plan with the -target option, which means that the result of this plan may not represent all of the changes requested by the current
│ configuration.
│ 
│ The -target option is not for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when
│ Terraform specifically suggests to use it as part of an error message.
╵

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: yes

aws_instance.demo_vm_1: Destroying... [id=i-0435cfff2020ce5fd]
aws_instance.demo_vm_1: Still destroying... [id=i-0435cfff2020ce5fd, 10s elapsed]
aws_instance.demo_vm_1: Still destroying... [id=i-0435cfff2020ce5fd, 20s elapsed]
aws_instance.demo_vm_1: Still destroying... [id=i-0435cfff2020ce5fd, 30s elapsed]
aws_instance.demo_vm_1: Still destroying... [id=i-0435cfff2020ce5fd, 40s elapsed]
aws_instance.demo_vm_1: Destruction complete after 40s
â•·
│ Warning: Applied changes may be incomplete
│ 
│ The plan was created with the -target option in effect, so some changes requested in the configuration may have been ignored and the output values may
│ not be fully updated. Run the following command to verify that no other changes are pending:
│     terraform plan
│ 
│ Note that the -target option is not suitable for routine use, and is provided only for exceptional situations such as recovering from errors or
│ mistakes, or when Terraform specifically suggests to use it as part of an error message.
╵

Destroy complete! Resources: 1 destroyed.

Validate the same by logging into the AWS Console.

However, to destroy both EC2 instances simply run terraform destroy without --target argument. Terraform validates the state and existence of the EC2 instances and triggers the resource deletion. Try running terraform destroy with our example now, and observe the output.

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

Changes to Outputs:
  - instance_id_1 = "i-0195745b98b21bec7" -> null

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: yes

aws_instance.demo_vm_2: Destroying... [id=i-0cdf2d51800624a22]
aws_instance.demo_vm_1: Destroying... [id=i-0195745b98b21bec7]
aws_instance.demo_vm_2: Still destroying... [id=i-0cdf2d51800624a22, 10s elapsed]
aws_instance.demo_vm_1: Still destroying... [id=i-0195745b98b21bec7, 10s elapsed]
aws_instance.demo_vm_2: Still destroying... [id=i-0cdf2d51800624a22, 20s elapsed]
aws_instance.demo_vm_1: Still destroying... [id=i-0195745b98b21bec7, 20s elapsed]
aws_instance.demo_vm_1: Still destroying... [id=i-0195745b98b21bec7, 30s elapsed]
aws_instance.demo_vm_2: Still destroying... [id=i-0cdf2d51800624a22, 30s elapsed]
aws_instance.demo_vm_2: Still destroying... [id=i-0cdf2d51800624a22, 40s elapsed]
aws_instance.demo_vm_1: Still destroying... [id=i-0195745b98b21bec7, 40s elapsed]
aws_instance.demo_vm_1: Destruction complete after 41s
aws_instance.demo_vm_2: Still destroying... [id=i-0cdf2d51800624a22, 50s elapsed]
aws_instance.demo_vm_2: Still destroying... [id=i-0cdf2d51800624a22, 1m0s elapsed]
aws_instance.demo_vm_2: Destruction complete after 1m7s

Destroy complete! Resources: 2 destroyed.

3. Destroy Protected Resources

Let us recreate the infrastructure we had in the previous example, this time with a minor difference. Add disable_api_termination = true attribute to demo_vm_2. Try to destroy the same using terraform destroy command again. Observe the output with error message.

As per the error message, we get OperationNotPermitted error for one of the EC2 instances. The Terraform configuration responsible for creating this EC2 instance has disable_api_termination set to true. This is additional protection provided by the cloud provider to avoid accidental deletion of the EC2 instance.

Because Terraform operations utilize cloud provider APIs to apply or destroy configurations, it cannot do anything disallowed by the provider’s API. In this case it means that Terraform is not be able to delete demo_vm_2. However, it was able to delete demo_vm_1 for which this property was not set at all. This tells us that it defaults to false.

Log in to AWS console and disable the termination property for this EC2 instance, and run the destroy command again. This time it should succeed.

destroy terraform resources

At this time, there is no way for Terraform to override this behavior. But this is a positive, because it helps prevent any accidental deletion of critical resources.

4. Destroy All Except a Few

At times you will face scenarios where you would like to recreate most of the infrastructure components, but keep a few critical ones in place. Currently, there is no way to specify the resources NOT to be destroyed using Terraform.

However, since the state plays a major role in Terraform’s decision making – an apparent workaround would be as follows:

  1. Remove the resource from the state file using terraform state rm command.
  2. Run terraform destroy – without Terraform --target argument.
  3. After successful destruction, import the target resources back in the state file. This post describes how to import cloud resources under Terraform.

Running terraform state rm lets Terraform know that some of the resources are not managed by Terraform anymore. When destroy is executed, Terraform does not touch those resources. When the cleanup of other resources is done, and the remaining resources are imported back – Terraform then manages the resources again.

Key Points

Terraform destroy is a command that should be used wisely. It is not something that would be used on a daily basis in managing the production environment. 

However, making use of it in sub-production environments would be quite frequent as a lot of try-outs for proofs-of-concept require cleanup activities.

Spacelift lets you customize the entire infrastructure life-cycle management by providing the ability to run pre and post commands at every stage – including the destroy phase – which can be very useful in keeping track of things.

We encourage you also to explore how Spacelift makes it easy to work with Terraform. If you need any help managing your Terraform infrastructure, building more complex workflows based on Terraform, and managing AWS credentials per run, instead of using a static pair on your local machine, Spacelift is a great tool for this. It supports Git workflows, policy as code, programmatic configuration, context sharing, drift detection, and many more great features. Create your free trial account or book a demo with one of our engineers

Spacelift destroying phase

Manage Terraform Better and Faster

If you are struggling with Terraform automation and management, check out Spacelift. It helps you manage Terraform state, build more complex workflows, and adds several must-have capabilities for end-to-end infrastructure management.

Start free trial
Terraform CLI Commands Cheatsheet

Initialize/ plan/ apply your IaC, manage modules, state, and more.

Share your data and download the cheatsheet