Declarative vs imperative
Describe the end state, not the steps.
IaC tools come in two philosophies, and understanding the difference explains how each behaves. An imperative approach describes the steps to reach a goal: "create a server, then install nginx, then start it." A declarative approach describes the desired end state: "there should be one server running nginx" — and the tool figures out what actions are needed to get there from wherever things currently are. Most modern IaC is declarative, and that choice has deep consequences.
Idempotence: the key property
The superpower of the declarative model is idempotence — applying the same configuration repeatedly produces the same result, making no changes if reality already matches the desired state. Run terraform apply when everything is already correct and it does nothing; run it after a resource was deleted and it recreates just that one. This is what makes IaC safe to run continuously: you are not issuing commands that might double-execute, you are asserting a desired state the tool converges toward. An imperative script that says "create a server" run twice makes two servers; a declarative config that says "one server" run twice still means one.
How declarative tools work: the reconcile loop
A declarative tool follows the same pattern you saw in Kubernetes: it compares desired state (your code) against current state (what actually exists) and computes the difference — what to create, change, or destroy — then makes only those changes. This "diff then converge" is why Terraform shows you a plan before applying: it is telling you the exact set of changes it computed to reconcile reality with your code. Understanding that the tool is always doing desired-minus-actual demystifies its behavior.