Declarative tools such as Terraform, OpenTofu, and Kubernetes manifests let you describe the desired end state and have a tool compute the steps to get there. With Terraform-style tools that computation compares three things:
- Configuration: what you wrote.
- State: what the tool believes it created, with IDs and attributes.
- Reality: what actually exists, refreshed from the provider.
The plan is the tool's proposal for reconciling them. Read it as a change review. Pay particular attention to -/+ (destroy then create). Renaming a resource, changing an immutable argument, or moving code into a module can turn an in-place update into the replacement of a database. moved blocks, lifecycle { prevent_destroy = true }, and import exist to keep identity stable across refactors.
Drift happens when someone changes reality by hand. The next plan will try to revert it. Decide deliberately whether to adopt the change into config or let the tool restore the declared state.
State is sensitive and shared. It must be locked during applies so two runs cannot interleave, and it should be stored remotely with versioning. It can also contain secrets.
Configuration-management tools like Ansible apply the same idea to hosts. A good playbook is idempotent: the second run reports no changes. If it does report changes, it is not describing a state. It is running a script.