Cloud  /  Terraform

IaC Terraform 50 guides · updated 2026

Infrastructure as code done right — providers, state, reusable modules, and the workflow patterns that keep multi-cloud deployments sane in 2026.

terraform taint and -replace

Sometimes a resource needs to be destroyed and recreated even when its configuration hasn’t changed — for example, a corrupted EC2 instance, a misconfigured security group, or a certificate that needs rotation. Terraform provides two ways to force this: the classic terraform taint command (soft-deprecated) and the modern -replace flag.


The Modern Approach: -replace Flag (Terraform 0.15.2+)

The recommended way to force recreation is the -replace flag on plan and apply:

Terminal window
# Preview what will be replaced
terraform plan -replace=aws_instance.web
# Force recreation — no taint step needed
terraform apply -replace=aws_instance.web
# Replace multiple resources
terraform apply -replace=aws_instance.web -replace=aws_eip.web_ip

This is safer than taint because:


The Classic Approach: terraform taint

terraform taint marks a resource as “tainted” in the state file, forcing Terraform to destroy and recreate it on the next apply. The resource continues to exist until apply runs.

Terminal window
# Mark a resource for recreation
terraform taint aws_instance.web
# Multiple resources
terraform taint aws_instance.web
terraform taint aws_security_group.web
# Taint a resource inside a module
terraform taint module.networking.aws_nat_gateway.main
# Taint a count-indexed resource
terraform taint 'aws_instance.app[2]'
# Taint a for_each resource
terraform taint 'aws_instance.app["web-server-1"]'

Then on next apply:

# aws_instance.web is tainted, so must be replaced
-/+ resource "aws_instance" "web" {
~ id = "i-old123" -> (known after apply)
}

Untainting a Resource

Terminal window
# Remove the taint marking without destroying the resource
terraform untaint aws_instance.web

When to Force Resource Recreation

ScenarioUse -replace or taint
EC2 instance acting up / corrupted filesystemYes
Certificate needs manual rotationYes
Auto Scaling launch config updated externallyYes
Lambda function deployment package needs refreshYes
RDS instance storage type not updatable in-placeYes
Kubernetes node needs replacement in node groupYes
Database password rotation (create new, update refs)Yes

Real Example: Replacing a Corrupted EC2 Instance

Terminal window
# 1. Drain traffic first (if behind a load balancer)
aws elbv2 deregister-targets \
--target-group-arn arn:aws:elasticloadbalancing:... \
--targets Id=i-1234567890abcdef0
# 2. Preview the replacement
terraform plan -replace=aws_instance.web_server
# Shows: -/+ aws_instance.web_server (tainted)
# Plan: 0 to add, 0 to change, 1 to replace
# 3. Apply the replacement
terraform apply -replace=aws_instance.web_server
# 4. Re-register with load balancer (or let Terraform handle via LB target group)

Difference Between taint and Changing Config

ApproachWhen to Use
terraform apply -replace=resourceResource is misbehaving but config is correct
Change config attribute that forces replaceYou want to change an immutable attribute (e.g., AMI, AZ)
terraform destroy -target=resource + applySame as replace but two explicit steps
lifecycle { create_before_destroy = true }Minimize downtime during forced replacements

Protect Against Unintended Replacement with create_before_destroy

When a resource must be replaced, Terraform destroys the old one first by default. For load-balanced services, this causes downtime. Use create_before_destroy to avoid it:

resource "aws_instance" "web" {
ami = data.aws_ami.latest.id
instance_type = "t3.medium"
lifecycle {
create_before_destroy = true
# New instance created → traffic shifted → old instance destroyed
}
}
Terminal window
terraform apply -replace=aws_instance.web
# With create_before_destroy: new instance comes up first, then old is terminated

Checking Taint Status in State

Terminal window
# List all resources and see if any are tainted
terraform state list
# Show details including taint status
terraform show
# Tainted resources appear with "tainted" annotation

terraform taint vs. -replace Summary

Featureterraform taint (classic)-replace flag (modern)
Terraform versionAll versions0.15.2+
WorkflowTwo commands (taint + apply)One command
State file changeYes (writes “tainted” status)No intermediate state change
Visibility in planYes (shows as tainted)Yes (shows -/+)
RecommendedNo (soft-deprecated)Yes

Use -replace for all new workflows. Understand taint for working with older Terraform versions or existing documentation.