Reading and Trusting the Plan

The four plan symbols and which two should stop you, why 'forces replacement' is the most important string in the output, the graph and parallelism, and the difference between applying a saved plan file and using auto-approve.

beginner 19 min lesson hands-on task included

The plan is the review artifact, not a formality on the way to apply. Almost every self-inflicted Terraform incident is visible in a plan somebody scrolled past.


Topic 1: The Four Symbols

SymbolMeaningRisk
+createLow
~update in placeLow — the resource survives
-/+destroy, then create a replacementHigh — a gap where nothing exists
-destroyHigh — data loss possible
Resource actions are indicated with the following symbols:
  -/+ destroy and then create replacement

  # aws_sqs_queue.work must be replaced
  -/+ resource "aws_sqs_queue" "work" {
      ~ arn  = "arn:aws:sqs:REGION:ACCOUNT_ID:work" -> (known after apply)
      ~ name = "work" -> "tasks" # forces replacement
        max_message_size = 262144
    }

Plan: 1 to add, 0 to change, 1 to destroy.

Two attributes changed here and only one mattered. arn changes because the resource is being replaced — a symptom. name carries # forces replacement, which is the cause.


Topic 2: Read the Summary Line First

Plan: 1 to add, 0 to change, 1 to destroy.

Before reading a single resource block, ask whether that shape matches what you changed. If you added one resource and the summary says 0 to add, 4 to change, 4 to destroy, something is wrong, and no amount of reading individual blocks is as informative as that mismatch.

Then hunt for - and -/+. Those are the only two symbols that can cause an outage.

forces replacement is the string to grep for:

Provider documentation marks which attributes force replacement. When you change one, the resource cannot be updated in place — the API has no rename — so Terraform destroys and recreates. Between the two, the resource does not exist.

If you need the change anyway, create_before_destroy inverts the order. That works when the platform permits two of the thing simultaneously — which for uniquely-named resources it often does not, and the apply fails rather than silently doing the wrong thing.

For a genuinely non-replaceable rename, the safe sequence is three deploys: create the new resource alongside the old, migrate traffic, then delete the old one separately.


Topic 3: The Dependency Graph and Parallelism

Terraform builds a directed acyclic graph of resources, data sources and modules. Edges come from attribute references (implicit) or depends_on (explicit).

terraform graph | dot -Tsvg > graph.svg

Terraform walks that graph in parallel wherever it can. Two security group rules attached to the same group are created simultaneously once the group exists.

terraform apply -parallelism=20     # default is 10

Raise it for large applies the API can absorb; lower it when you hit provider rate limits. Circular dependencies are detected and reported at plan time — the fix is refactoring, not more depends_on.


Topic 4: plan Without apply

terraform plan                      # print the plan, no option to apply
terraform plan -out=change.tfplan   # save it to a file
terraform plan -destroy             # preview a full teardown
terraform plan -refresh-only        # detect drift without proposing config changes
terraform plan -target=module.net   # limit scope — use sparingly

Saving to a file is what makes pipelines safe.


Topic 5: Saved Plan vs. Auto-Approve

Both skip the confirmation prompt. They are not equivalent, and the difference is a production safety property.

terraform apply change.tfplan     # execute exactly this reviewed plan
terraform apply -auto-approve     # compute a fresh plan and run it unseen

Applying a saved plan file tells Terraform: execute precisely this. If reality moved since the plan was generated — someone else applied, a resource was deleted — Terraform errors out rather than doing something you did not review.

-auto-approve tells Terraform: work out what to do now and do it without asking. If the plan it computes destroys your database, it destroys your database.

This is why pipelines split plan and apply into separate jobs, publish the plan as an artifact for review, and pass that same file to apply. Treat -auto-approve as a local convenience for throwaway environments.


Topic 6: A Habit Worth Building

Read plans in this order, every time:

  1. Summary line. Does the shape match the change you made?
  2. Destroys and replacements. Search for - and -/+ first.
  3. forces replacement markers. Which attribute caused it, and did you mean to change it?
  4. (known after apply) values. Fine on create; on an existing resource they mean something is being recomputed.
  5. Everything else. Usually uninteresting, and that is the point.
terraform show change.tfplan            # human-readable
terraform show -json change.tfplan      # machine-readable, for policy checks

The JSON form is what policy engines evaluate in CI — a later lesson uses it to block non-compliant changes before they reach an environment.


Try it yourself: Save a plan to a file, then change something in the console before applying it. Run terraform apply change.tfplan and read the error. That refusal is the safety property you are buying.

Common mistake: Skimming to the summary and approving because the counts look small. 1 to destroy on a stateful resource is a bigger event than 40 to add. The counts tell you the shape; only the symbols and forces replacement markers tell you the risk.