DevOpsInterviews logo
← Infrastructure as Code & Configuration / 13
mediumHashiCorpFlipkartUber

An apply ran in an order that broke the deploy. How does Terraform decide ordering, and where does depends_on fit?

Everyone recites that depends_on forces ordering. The stronger half of the answer is the graph you never see: implicit edges from references, why file layout orders nothing, and what explicit edges cost.

Grounded in researched DevOps, SRE and platform engineering interview loops, written to a senior-engineer editorial bar, and never padded to hit a word count.

TL;DR: Order comes from the dependency graph Terraform builds out of references in your expressions, never from file position or declaration order. Explicit depends_on exists for ordering the language cannot infer, and every explicit edge couples the downstream resource to the entire upstream one, so it is a scalpel rather than a habit.

How to approach it

Start with the implicit mechanism, then give the situations where only an explicit edge works, then the cost of over-using it. Naming a real cycle error you have debugged earns credibility here.

A strong answer

Terraform parses every expression and draws an edge whenever one resource references another: an IAM role ARN fed into a lambda function means the role is created first, updated first, and destroyed last, no matter which file either block lives in. Within that directed acyclic graph, independent branches run concurrently up to the parallelism limit (default 10), which is why splitting one monolithic state into components also speeds applies. File layout is pure readability; moving a block to the top of the file orders nothing.

Explicit depends_on covers the cases references cannot see. This fragment omits the Lambda code, runtime and handler arguments:

resource "aws_lambda_function" "api" {
  function_name = "orders-api"
  role          = aws_iam_role.api.arn

  # policy attachment is referenced nowhere,
  # yet the function needs it before its first invocation
  depends_on = [aws_iam_role_policy_attachment.logs]
}

The canonical cases: hidden permission dependencies, where the attachment operation must finish first. Completion does not guarantee IAM propagation; provider retries or a bounded readiness check must handle eventual consistency; bootstrap sequencing, where a provider configuration itself is built from resources; and side effects such as a seed script nothing references downstream. The catch is coarseness. depends_on makes the function depend on the whole attachment object and everything upstream of it, so unrelated churn now re-evaluates the lambda too. Heavy use serialises graphs and slows applies without adding correctness. Prefer a direct value reference when it expresses the true dependency. A wrapper output or trigger resource does not erase underlying dependencies.

Cycles are the rite of passage: resource A references an attribute of B while B's count or condition references A, and plan fails with a cycle error naming the loop. Break the actual dependency cycle by separating phases or making shared configuration independent. A local or output that retains the same references retains the cycle. Destruction walks the same graph in reverse, so "deleted in the wrong order" usually means a missing reference left the two resources independent rather than related.

What interviewers probe next

"depends_on versus a plain reference for ordering?" A reference orders and passes data, which is the default and best case. depends_on only orders and couples coarsely; reach for it when there is no value to pass.

"How do you inspect the graph before applying?" terraform graph piped to Graphviz for small roots, TRACE plan logs for large ones, and the cycle error itself, which names the offending nodes.

"Can depends_on hold expressions?" It requires a static list of references to resources or child modules; arbitrary computed expressions and a local containing the list are not valid substitutes.

Common mistakes

Sprinkling depends_on across a codebase to make applies "deterministic", serialising the graph while burying the real data flow.

Using it to paper over eventual-consistency races that a retry policy or the resource's own timeouts block should absorb.

Diagnosing ordering problems by shuffling declarations between files, which changes nothing.

Sources: depends_on reference.

That one was free, and so are 18 answers per topic without an account. Signing in doubles that to 28, keeps your bookmarks, and tracks which topics you keep getting wrong.one Google click · no card · nothing to cancel
HOW DID IT GO?
0
UP NEXT ON YOUR JOURNEY
NOTES & DISCUSSION · 0

Nothing here yet. Say how you would answer it.