Terraform's whole job is to make your real infrastructure match the infrastructure you described in code. The plan / apply cycle is how it gets there safely: look before you leap, then leap.
The state file ties it together
Terraform keeps a state file recording what it believes already exists. Every command compares three things: your .tf config (desired), the state (last known), and the real world (actual). That comparison is what produces a plan.
terraform plan — the dry run
plan computes the diff and prints it without changing anything. You read it for the symbols: + create, - destroy, ~ update in place, and the dreaded -/+ (destroy andrecreate — which can mean downtime or a new IP). The golden rule: if the plan surprises you, stop and find out why before you apply.
terraform apply — make it real
apply executes a plan, creating, changing, and deleting resources in dependency order, then updates the state file. Run interactively it shows the plan again and waits for you to type yes — that prompt is the last safety gate, so actually read it.
terraform destroy — tear it down
destroy removes everything in the state. Invaluable for cleaning up test environments, terrifying if pointed at production — which is exactly why you want to have made that mistake somewhere safe first.
Run the cycle for real
Reading about plan and apply only takes you so far; watching a plan turn into running servers is where it sticks. Write HCL and run plan/apply/destroy against a live fleet with hands-on Terraform practice.