How Terraform detects out-of-band infrastructure drift and preserves resource identity during configuration refactors.
Drift occurs when a managed remote object changes outside the configuration-and-apply workflow, so its actual attributes no longer match Terraform’s recorded and desired model. A normal plan refreshes existing objects by default and can surface that difference. Investigate whether the change was intentional, an incident response, or an unauthorized change before deciding whether to update configuration or restore the intended infrastructure.
Use refresh-only mode when the purpose is to reconcile state and root outputs with known out-of-band changes, not to make normal desired-state changes:
1terraform plan -refresh-only
2terraform apply -refresh-only
HashiCorp’s plan reference defines refresh-only mode, and its refresh documentation recommends this reviewed workflow instead of the deprecated terraform refresh command. Review the plan before applying: a refresh-only apply changes state, even though it does not modify remote objects.
Do not use -refresh=false as a routine shortcut. It can hide out-of-band changes and produce an incomplete plan. Use it only when its trade-offs are understood for a specific operation.
Renaming a resource block changes its Terraform address. Without an explicit refactor instruction, Terraform can interpret that as “destroy the old address and create the new one.” A moved block tells Terraform that the existing object should follow the new address instead.
1resource "aws_instance" "api" {
2 # configuration omitted
3}
4
5moved {
6 from = aws_instance.web
7 to = aws_instance.api
8}
HashiCorp’s refactoring guidance explains that Terraform v1.1 and later uses the block to update the address in the next plan without destroying the object. Keep historical moved blocks in reusable modules unless it is safe to break the upgrade path for every user.
For a resource that should leave Terraform management while remaining in the provider, use a removed block with the appropriate lifecycle setting rather than deleting its configuration and assuming Terraform will preserve it. The removed block reference documents this distinction.