Lesson 0006 · Understand Terraform

The apply lifecycle & the graph

One idea · ~12 min. Apply is a parallel graph walk with no rollback — order comes from references, recovery comes from state.
Why this next? Lesson 0001 gave you what plan computes. This is what apply executes — the other half of your "plan/apply lifecycle" black box. It explains the two scariest moments in real Terraform: a replace on a live resource, and an apply that dies halfway.

Terraform compiles your config into a DAG — a dependency graph. Every reference is an edge: subnet uses aws_vpc.main.id, so the VPC goes first. Apply walks the graph, running each node as soon as its dependencies finish — up to 10 at once by default. File order, alphabetical order, the order you wrote things: all irrelevant. Only the graph decides.

Two kinds of edges

Implicit — any expression reference. This is 95% of your graph and it's free. Explicit — depends_on, for dependencies the config can't see: the classic is an app instance that needs an IAM role's policy attachment to exist before boot, but only references the role itself.

Code smell: depends_on where a reference would do. It coarsens the graph and hides the real relationship from the next reader.

A replace is two nodes

That -/+ from lesson 0001? Internally it's a destroy node + create node, because destroy order is the reverse of create order. Default sequence: destroy old → create new — which is a downtime window. lifecycle { create_before_destroy = true } flips it: new first, then old — zero gap, but old and new must coexist, which unique-name resources can't do. That's why it's opt-in.

The no-rollback rule. Terraform is not transactional. When resource 4 of 7 fails, resources 1–3 stay created and stay in state, the half-created one is marked tainted, and 5–7 are never attempted. Recovery isn't restore-from-backup — it's fix the cause and apply again: the graph walk resumes from wherever reality is. This is why state exists instead of transactions.

You're watching the apply — you call it

✅ Prove it on your own machine (optional, 5 min)

  1. Write 3 terraform_data resources where C references B's output and B references A's. Apply and watch the strict A→B→C ordering.
  2. Remove the references — apply again and watch all three run concurrently.
  3. Run terraform graph on any real config; paste the DOT output into an online Graphviz viewer and find your longest dependency chain.
  4. Make a resource fail mid-apply (e.g. an invalid AMI ID on the second of two instances) — then inspect terraform state list: the first instance is there. No rollback.
💬 Good follow-ups: "How do data sources fit in the graph — when do they read?" · "Why does destroy order have to be the reverse of create order?" · "What exactly does state lock during a partial apply failure?"