Chapter 3 of 24

Resources and the Dependency Graph

Configuration order is for people; references define the graph the CLI can safely execute.

Learning objectives

The graph is the execution plan

Resource

Manages a real object and has an address such as aws_vpc.main.

Data source

Reads an existing object. It is still a dependency and can fail or drift.

Local and output

Locals name repeated expressions; outputs expose selected graph results.

Dynamic block

Generates repeated provider nested arguments; it does not replace resource-level for_each.

resource "aws_subnet" "app" { vpc_id = aws_vpc.main.id } # implicit edge
resource "aws_route_table_association" "app" { depends_on = [aws_route.app] }
resource "aws_security_group" "rule" {
for_each = var.rules
dynamic "ingress" {
for_each = each.value.ingress
content { from_port = ingress.value.from_port }
}
}

count uses numeric addresses such as [0]; inserting an item can retarget them. Prefer for_each with durable names when objects have identity.

Default: write a real attribute reference first. Use depends_on only for an ordering dependency that has no value to reference.

AWS context

This lab uses only the built-in terraform_data resource. Later, the same edges will connect VPCs, subnets, route tables, and IAM objects, where a missing edge can produce a race or invalid API call.

Lab: inspect a small graph $0

Open labs/03-graph/main.tf. One resource implicitly consumes the network output, a second intentionally waits for all keyed subnets, and a separate count resource makes the address difference visible.

Terraform

cd learn-terraform/labs/03-graph
terraform init -backend=false
terraform graph
terraform plan

OpenTofu

cd learn-terraform/labs/03-graph
tofu init -backend=false
tofu graph
tofu plan

Save the DOT graph if Graphviz is available: tofu graph | dot -Tsvg > graph.svg.

Read addresses and edges

Expect six resources: network, two keyed subnets, two numbered replicas, and completion. In the graph, trace subnet to network, then graph_complete to the subnet collection.

SignalReview question
subnet["app-a"]Does the key match durable object identity?
replica[0]Would insertion reorder this address?
depends_onIs there truly no attribute reference that could encode this edge?

Failure drill: a cycle

Do not add a back-reference from network to a subnet. Two nodes that require each other produce a cycle error; remove the artificial edge and model a separate attachment resource if the API requires a second phase.

Do not use file order as a dependency: it is not a graph edge and will not serialize an apply.

Verify

  1. Run terraform graph or tofu graph.
  2. Find the network-to-subnet implicit edge.
  3. Confirm the explicit completion node waits for the subnet collection.
  4. Confirm keyed and indexed addresses differ in the plan.

Cleanup

Stop at plan. If you apply while exploring, run terraform destroy or tofu destroy with the same CLI. No AWS object is involved.

Quick check

What normally creates an edge?

An attribute reference, such as a subnet consuming a VPC ID.

When is depends_on appropriate?

For a real ordering dependency that cannot be represented by an attribute reference.

Why prefer for_each for named subnets?

Named addresses remain associated with the same object when another key is added.

Recap and next

Terraform and OpenTofu schedule a dependency graph, not a script. Stable addresses and explicit data flow make a plan easier to trust.

Next: Chapter 4, The Plan and Apply Lifecycle.