What is the difference between `terraform taint` and `terraform apply -replace`, and how does forced replacement work?

4 minadvancedterraformreplacetaintcli

Quick Answer

`terraform taint <address>` (deprecated in modern Terraform) marked a resource in state as "needs recreation" so the *next* plan would destroy and recreate it, but that mutation happened outside of any plan, invisibly. `terraform apply -replace=<address>` is the modern equivalent — it forces a specific resource's replacement as part of a normal, reviewable plan, showing the destroy+create in the plan output before you confirm. Both are useful when a resource is broken/misconfigured in a way Terraform's normal diff won't detect (e.g., corrupted instance) and needs an explicit, deliberate replace.

Detailed Answer

Both mechanisms exist to force Terraform to replace a resource that its normal plan/diff logic wouldn't otherwise flag for replacement — but they differ significantly in visibility and modern support.

terraform taint (deprecated)

terraform taint aws_instance.web

This marked a resource in state as tainted, meaning "the next plan should destroy and recreate this" — but the marking itself happened immediately, as a direct state mutation, completely outside of any reviewable plan. You'd only see the consequence (a forced replace) on the next terraform plan, and there was no way to preview the replace in the same step you requested it. It's deprecated in modern Terraform versions in favor of the option below.

terraform apply -replace (modern approach)

terraform apply -replace="aws_instance.web"

or, to preview first:

terraform plan -replace="aws_instance.web"

This forces the replacement of a specific resource as part of a normal, reviewable plan — the plan output explicitly shows the destroy+create for that resource (marked -/+) alongside anything else that would change, and you approve it the same way as any other apply. Nothing happens silently; the forced replacement is visible in the same plan output you'd review for any other change.

When you'd use this

  • A resource is misconfigured or corrupted in a way that isn't reflected in any attribute Terraform's diff would catch (e.g., a VM with a stuck/corrupted disk that provider APIs still report as "running fine").
  • You want to force a rolling replacement (e.g., to pick up a new AMI baked with the same ID, or to "reset" a resource) without changing any configuration value that would otherwise trigger it.

Interview-ready summary

Both force replacement of a resource outside Terraform's normal diff-driven decision-making, but -replace does it as an explicit, visible part of the standard plan/apply flow, while the older taint command mutated state directly and only showed its effect on a subsequent, separate plan — which is exactly why it was deprecated in favor of the more transparent -replace flag.

Related Resources