While Terraform is great for deploying (and destroying!) resources, you occasionally run into a situation where you need Terraform to recreate an existing resource. Enter the Terraform taint and replace commands!
In this post, you will learn about using both of these commands, when you should use each one, and some examples of recreating resources.
Using Terraform taint Command
The terraform taint
command instructed Terraform that a managed resource was degraded or damaged. Terraform then marked the object as “tainted” in the state file and replaced the object in the next plan you created.
The syntax for the command is terraform taint [options] address
. The address
argument indicates which resource to mark as tainted and is formatted in the resource address syntax. You find the resource address by using the terraform state list
command. This command shows the deployed resources from the state file.
For example, here is a basic Terraform configuration file using the azurerm provider to deploy a resource group, a virtual network, three subnets, and a storage account.
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
}
}
}
provider "azurerm" {
features {}
}
# Deploy resource group
resource "azurerm_resource_group" "rg" {
name = "rg-tfdemo"
location = "WestUS2"
}
# Deploy virtual network
resource "azurerm_virtual_network" "vnet" {
name = "vnet-prod"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
address_space = ["10.0.0.0/8"]
}
# Deploy subnets using count
resource "azurerm_subnet" "snets" {
count = 3
name = "subnet${count.index + 1}"
address_prefixes = ["10.${count.index + 1}.0.0/16"]
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
}
# Deploy a storage account
resource "azurerm_storage_account" "sa" {
name = "jbtterraformdemo3579"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
account_replication_type = "LRS"
account_tier = "Standard"
access_tier = "Hot"
}
When you deploy this configuration, the results of the terraform state list
command are shown below with each resource’s address. The [0]
, [1]
,and [2]
indicate each subnet created using the count
argument.

To force recreate the storage account resource, copy the azurerm_stroage_account.sa address representing the storage account. Next, use this with the terraform taint
command, like the example below. Once executed, Terraform will indicate that the resource is tainted
# Taint a resource for replacement
terraform taint azurerm_storage_account.sa

Next, run terraform plan -out=deploy.tfplan
, and Terraform displays that the storage account resource is tainted and will be replaced.

Finally, run terraform apply deploy.tfplan
to deploy the planned changes. Terraform destroys the storage account resource and creates a new one.

Using Terraform replace command
HashiCorp deprecated the terraform taint
command in v0.15.2. If you want to force replacement of an object even though there are no configuration changes, use the terraform plan
or terraform apply
command with the -replace
option instead. If you are using an older version of Terraform, continue using the terraform taint
command.
The “replace” option is superior to “taint” as you can see the full effect of the change before you take any action. When you use taint, someone else can create a new plan against your tainted object before you reviewed the consequences of the change yourself.
If you want to create an execution plan and mark an object for replacement, use the terraform plan command. Add the -out=FILE option to save the generated plan to a file, and add the -replace=ADDRESS option to indicate the object. Use the same resource address found in the previous section.
# Create an execution plan with the replaced object
terraform plan -out="deploy.tfplan" -replace="azurerm_storage_account.sa"
# Execute the plan to replace the object
terraform apply deploy.tfplan
If you don’t want to create a plan, you can also mark the object for replacement directly in the terraform apply command. This example marks one of the subnets for replacement.
terraform apply -replace="azurerm_subnet.snets[0]"
Terraform outputs that the subnet will be replaced (as requested), and you need to enter “yes” to approve the change.

Closing
Terraform taint and replace provides multiple ways to replace managed objects depending on your version of Terraform. If you upgrade to a newer version, consider using the new replace method as this is the HashiCorp recommendation.
Enjoyed this article? Check out more of my Terraform content here!
Pingback: Public “Office Hours” (2021-09-29) | Cloud Posse