Dependencies · 11 min read

How Terraform dependencies work

Terraform does not create blocks from top to bottom. It builds a dependency graph from the values resources reference. When a subnet reads a VPC ID, Terraform knows the VPC must be created first—even if the blocks live in different files.

A direct dependency reference

The subnet needs the VPC ID. That reference is what lets Terraform infer that the VPC must be created first.

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}

resource "aws_subnet" "public" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "10.0.1.0/24"
}

Implicit dependencies are the preferred default

aws_vpc.main.id communicates both the value the subnet needs and the order Terraform should use. This direct reference is an implicit dependency and normally gives the clearest description of the architecture.

References can use IDs, ARNs, names, locations, or other exported attributes. The cloud display name is not necessarily the Terraform local name, so match the declared type and local name exactly.

When depends_on is appropriate

Use depends_on for a genuine hidden ordering requirement, such as an IAM policy attachment that must exist before a service starts but is not otherwise passed as an input value.

Keep it small and explainable. If a direct attribute reference is available, it is usually better because it models both the data flow and the creation order.

Cycles need a design change

A cycle means Terraform cannot decide what to create first because resources require each other’s values. Read the cycle error as a path through the graph and identify the reference that closes the loop.

The answer is usually to separate creation from later configuration or use a value available earlier. File order and extra depends_on entries cannot break a true cycle.

Put it into practice

Paste the example into Build and follow the subnet arrow to the VPC. Rename main to an undeclared name, read the validation message, then correct it by copying the declared address.

  1. Read a reference as type.name.attribute.
  2. Confirm its resource type and local name were declared.
  3. Prefer direct references when a real value is needed.
  4. Use depends_on only for a prerequisite Terraform cannot infer.