Suppose one Terraform data source needs the ID returned by another. The order of their HCL blocks does not matter: Terraform identifies the reference and schedules the lookup that supplies the ID first. It does the same across larger infrastructure configurations, where writing every action in execution order would be impractical. section 2.2.5
A directed acyclic graph (DAG) represents these dependencies. Its nodes represent resources, and its directed relationships establish which resources must come before others. “Acyclic” means the relationships cannot loop back to their starting point. Terraform’s resource graph underpins its operations; state is essentially a snapshot of resources in that graph. section 5.2
Listing 2.15 A data source being referenced by another data source
data "aws_vpc" "default" {
default = true
}
data "aws_subnets" "default" { #1
filter {
name = "vpc-id"
values = [data.aws_vpc.default.id] #2
}
}
The subnet lookup uses the VPC lookup’s ID. That attribute reference gives Terraform the dependency it needs without relying on file order. section 2.2.5
During `terraform plan`, Terraform refreshes its view of infrastructure, compares it with the configuration, and builds a DAG of proposed actions. `terraform apply` then runs the plan. To inspect relationships visually, use `terraform graph` to produce a graph file that a tool such as GraphViz can render. Attribute references usually establish dependencies automatically; `depends_on` can specify one directly. section 1.4.3 section 2.2.5
Listing 5.10 Services with circular dependencies
resource "null_resource" "alpha" { #1
triggers = { #2
rebuild = null_resource.charlie.id #3
}
}
resource "null_resource" "bravo" {
triggers = {
rebuild = null_resource.alpha.id #4
}
}
resource "null_resource" "charlie" {
triggers = {
rebuild = null_resource.bravo.id #5
}
}
Each resource’s trigger refers to another resource in a chain that returns to its start. No valid dependency order exists, so `terraform plan` reports a cycle error. section 5.7.1
When a cycle appears, trace the resources named in the error and find the references connecting them. If they only need a shared value, a variable or local value may replace a resource-to-resource reference. The accompanying fix uses one variable for all three triggers; a more complex cycle may instead signal that the architecture needs revisiting. section 5.7.1
Listing 5.11 Removing circular dependencies
variable "build_id" { #1
default = null
type = string
}
resource "null_resource" "alpha" {
triggers = {
rebuild = var.build_id #2
}
}
resource "null_resource" "bravo" {
triggers = {
rebuild = var.build_id
}
}
resource "null_resource" "charlie" {
triggers = {
rebuild = var.build_id
}
}
Compare this configuration with the cycle: the triggers now read a shared variable rather than one another’s resource IDs. section 5.7.1














