In Terraform, what does `terraform apply -replace="aws_instance.web"` do, and when would you reach for it instead of editing the configuration?
answer
- force one resource to be rebuilt
- config is fine, reality is not
- the modern successor to taint
- appears as a planned replacement
- address must include the count or for_each key
basics
~20 sTerraform's -replace option plans a destroy-and-recreate of one named resource instance without any configuration change. You reach for it when the real resource is broken or half-built while its configuration and recorded state still look correct.
solid answer
~40 s`-replace=ADDRESS` tells Terraform to plan a replacement of that one object even though nothing in the configuration or the refreshed attributes changed. It is a planning option rather than a state edit: you can run `terraform plan -replace=...` first, see the object marked for replacement in the diff, and simply not apply it if that is not what you wanted. It superseded the older `terraform taint` workflow, which mutated state immediately and could not be reviewed. The typical use is a machine whose bootstrap failed, or a resource a provider left half-created — the config is right, the real thing is not. The address must name a single instance, so with `count` or `for_each` you include the key, as in `-replace='aws_instance.web[0]'`. Treat it as destructive: the default order is destroy, then create.
code
bash · 3 linesterraform plan -replace='aws_instance.web[0]' -out=replace.tfplan
terraform show replace.tfplan
terraform apply replace.tfplango deeper
Be ready to say plainly that this option schedules a destroy and recreate of one resource on the next apply, and that you never edit the configuration to get it.
Explain that it is a plan-time option rather than a state mutation, why that made the taint command obsolete, and how the address changes when the resource uses count or for_each.
Show the operating discipline: plan first, read what the replacement forces to update downstream, check for data loss and prevent_destroy, and pick the create-before-destroy ordering deliberately when something live depends on it.
Own the question of whether hand-driven recreation should be normal at all. Repeated manual replacements usually mean the resource should be rebuilt from configuration or from an image pipeline, not from an operator's shell history.
## The problem it solves Terraform decides what to do by comparing three things: your configuration, the recorded state, and the refreshed real-world attributes. When all three agree, the plan is empty — even if the resource is useless. An EC2 instance whose user-data script failed halfway still has the right instance type, the right subnet and the right tags; nothing Terraform can see is wrong. `-replace` is the way to say "I know it looks fine; rebuild it anyway." ## What the option does `-replace=ADDRESS` is accepted by `terraform plan`, `terraform apply` and `terraform destroy`. Terraform resolves the address against the objects in state and plans a **replace** action for it: destroy the existing object, then create a new one from the same configuration. If the resource sets `create_before_destroy` in its `lifecycle` block, the replacement follows that order instead. Crucially, it changes the *plan*, not the state. Nothing is written until you apply, the replacement appears in the diff for a reviewer to see, and backing out means not applying. You can pass the option more than once to replace several objects in one run. ```bash terraform plan -replace='aws_instance.web[0]' -out=replace.tfplan terraform apply replace.tfplan ``` ## Why it replaced taint Before Terraform 0.15.2 the same intent was expressed as `terraform taint aws_instance.web`, which immediately wrote a "tainted" marker into state as a side effect, before anyone had seen a plan. Getting it wrong meant remembering `terraform untaint`, and in an automated pipeline the intent never showed up in the plan the reviewer read. `-replace=` folds the whole thing into the normal propose-then-approve cycle. `terraform taint` and `terraform untaint` still exist in Terraform 1.x for compatibility but are deprecated, and interviewers frequently use the pair to check whether you have kept up. The tainted *status* has not disappeared, because Terraform still sets it on its own: if a create-time provisioner fails, the object exists but its post-create steps did not finish, so Terraform marks it tainted and the next plan proposes a replacement. That is Terraform flagging a half-built object, not a user command. ## Addressing rules The address must identify **one resource instance**, not a whole resource with multiple instances: - plain resource: `-replace='aws_instance.web'` - with `count`: `-replace='aws_instance.web[1]'` (indexes start at 0) - with `for_each`: `-replace='aws_instance.web["blue"]'` - inside a module: `-replace='module.workers.aws_instance.node[0]'` Quote the address in a shell — brackets and quotes are otherwise eaten by the shell. There is no wildcard form; replacing thirty instances means thirty addresses, and if you find yourself doing that, the thing you actually want is a configuration change that forces replacement for everyone. ## What it does not do It does not replace the resources that *depend* on the one you named. Those may still show updates in the plan, because attributes they reference — an id, a private IP, an ARN — become unknown until the new object is created, so Terraform plans to update whatever consumes them. Read that part of the diff: replacing one instance can quietly re-register a load-balancer target or rewrite a DNS record. It is also not a substitute for fixing configuration. If a resource needs rebuilding every time some upstream value changes, that relationship belongs in the configuration — Terraform's `lifecycle` block has a meta-argument for exactly that — rather than in an operator's shell history. ## Operational care Replacement is destructive by definition. On a database, a volume, or anything holding data, destroy-then-create means the data is gone; a `prevent_destroy` lifecycle setting will make the plan fail outright, which is the guardrail working. Always plan first and read the diff before applying, and prefer applying a saved plan so that what was reviewed is exactly what runs. Finally, distinguish `-replace` from its neighbours. `-replace` changes *what action* is planned for an object. `-target` changes *which objects* are considered at all. They answer different questions, and mixing them up is the most common way this topic goes wrong in an interview.
- Why is -replace considered safer than the old taint command?Because it changes the plan instead of the state. `taint` wrote a marker into state the moment you ran it, before anyone reviewed anything, and undoing it needed a second command. With `-replace` the replacement shows up in the diff, a reviewer sees it, and not applying is a complete rollback. It also fits pipelines that apply saved plans.
- You pass -replace for one instance of a resource that has count = 5. What happens to the other four?Nothing directly — only the addressed instance is planned for replacement. The others keep their existing objects. Resources that reference the replaced instance's attributes may still show updates, because those attributes become unknown until the new object exists, so Terraform plans to reapply whatever consumes them.
- What stops -replace from destroying a production database by accident?A `prevent_destroy = true` lifecycle setting on the resource makes the plan fail rather than proposing the destroy, which is exactly why stateful resources carry it. Beyond that, the only protections are process ones: plan first, read the diff, and apply a saved plan so what runs is what was reviewed.
saying these in an interview costs you the question
- Says -replace mutates state immediately, the way taint did
- Thinks one -replace rebuilds every instance of a count-ed resource
- Assumes replacement is harmless because the config did not change
- Reaches for terraform state rm plus re-import to rebuild a resource
- Believes dependent resources are automatically replaced too