Prepare a bounded experiment
This lesson reorganizes configuration for a fictional settlement service while preserving its binding to the managed object. Before discussing commands, write three invariants: the intended object retains identity, the plan contains no unauthorized replacement, and one owner controls the operation. The lab uses Terraform 1.16.5, built-in terraform_data, and local state in a fresh temporary directory. There are no external providers, cloud services, provisioners, or credentials. The resource stores values to observe lifecycle behavior; it does not represent a database or an available service. This lets you observe addresses and actions without affecting real infrastructure.
Observe the plan before correcting it
Start with resource "terraform_data" "ledger" { input = "settlement-v1" }. In the isolated directory, run init, validate, and apply. Record the address and ID through show -json without publishing the full state. Then change only ledger to settlement and save a plan with plan -out=rename.plan. The lab observed delete for terraform_data.ledger and create for terraform_data.settlement. It did not apply that plan. Explain to a colleague why equal input does not tell Terraform to preserve identity: the relationship between addresses was missing. This negative exercise is useful because it shows the effect before adding the corrective mechanism.
Map and confirm identity
Add a moved block with from = terraform_data.ledger and to = terraform_data.settlement. Generate a new plan, move.plan, and inspect it with show -json move.plan. In the lab, previous_address identified ledger and actions showed no-op for settlement. After applying exactly move.plan, the address changed and the ID stayed the same. These are separate observations: the plan describes the proposal; subsequent state confirms application in this example. For a real change, also review attributes that may require replacement. A correct moved block does not approve additional physical changes. If refactoring and an upgrade are combined, consider separating them to make the operational decision understandable.
Build a correspondence table
Before moving from count to for_each, prepare a table: old address, observed object, intended key, and confirmation owner. In the exercise, worker[0] corresponds to Lisbon and worker[1] to Paris; new keys are lisbon and paris. Alphabetical city order is not evidence of the old binding. Confirm correspondence and write each instance mapping. If earlier versions used a, then b, and now c, include consumers skipping versions when reviewing history. A team already on b may upgrade correctly while another still on a loses its path. A consumer matrix avoids validating only the newest environment.
Stop management and organize handover
The second objective is to stop managing an object while retaining defined ownership. In the lab, the resource was replaced by removed with from = terraform_data.settlement and lifecycle { destroy = false }. The plan showed forget; after application, the entry disappeared from state. Because terraform_data creates no remote object, this test does not demonstrate survival of cloud storage. In a real handover, the source plan is only part of the evidence. Confirm who may apply, object identity, destination adoption plan, dependencies, retention, and costs. If the destination imports a different configuration, it may propose additional changes. Do not close the task merely because the source no longer shows the resource.
Deliver useful evidence to operations
Prepare a short change-meeting note: code revision, before and after addresses, proposed actions, actually approved plan, subsequent confirmation, and recipient follow-up. Share only necessary fields: show -json can expose sensitive values. To reproduce local results, the repository includes content/labs/terraform-state/run.py; run it with the absolute path to a 1.16.5 CLI. The runner creates and removes its temporary directories and checks six groups of observations. The archive used in this review was compared with the published SHA256; signature validation was not performed. Summary: identity, physical action, and ownership are three distinct questions. Connect this lesson with modules, locking, import, and partial recovery.
ledger→settlement without moved proposes delete/create; with moved, the lab preserved ID.
Common pitfalls
Equating names with identity; ignoring additional replacements; confusing forget with destination adoption.
Related topics: Plans and validation · Modules and identity · Adoption and recovery
Confirm mapping, read full actions, and complete the ownership handover.
Reference: Refactor modules · Terraform v1.16 concepts; official documentation consulted 2026-09-30; provider and backend capabilities must be confirmed