Terraform path · The model · Topic 4 of 14

Dependencies: references and depends_on

Not started

Terraform turns your configuration into a **dependency graph**. Each resource, data source, module, variable and output is a node; each reference from one to another (aws_vpc.main.id, random_pet.service.id) is an edge. It then walks the graph, running independent nodes in parallel (10 at a time by default) and dependent ones in order. Where blocks sit in which file has no effect at all.

Why it matters: Terraform creates, updates and destroys in parallel wherever it can. Getting the dependency graph right is what keeps it from creating a server before its network, or deleting a role while something still uses it.

  1. 1References create edges

    When one resource's argument refers to another's attribute, Terraform orders them automatically. This covers almost every case.

  2. 2Order in files does not matter

    Terraform builds a graph from references. Blocks can be in any file, in any order.

  3. 3depends_on is for hidden dependencies

    Use it only when a dependency exists that no reference expresses, such as a policy that must be attached before an app starts.

  4. 4Destroy runs backwards

    Dependents are destroyed before what they depend on, the reverse of creation.

1

How it works

The explanation, with examples you can run.

Implicit dependencies

Most dependencies come for free. In this module, the file's name uses the pet's ID, so Terraform must create the pet first:

resource "random_pet" "suffix" {  prefix = "${var.env}-${var.name}"} resource "local_file" "manifest" {  filename = "${path.root}/out/${random_pet.suffix.id}.txt"  content  = "name=${random_pet.suffix.id}\n"}

Calling it twice with for_each (Terraform 1.16.6) shows both rules at once: the two independent instances run in parallel, and inside each, the file waits for its pet:

module.service["api"].random_pet.suffix: Creating...module.service["worker"].random_pet.suffix: Creating...module.service["worker"].random_pet.suffix: Creation complete after 0s [id=dev-worker-workable-duck]module.service["api"].random_pet.suffix: Creation complete after 0s [id=dev-api-literate-dingo]module.service["api"].local_file.manifest: Creating...module.service["worker"].local_file.manifest: Creating...module.service["worker"].local_file.manifest: Creation complete after 0s [id=1e347b775a439277176c252f6080a6f7871c7c22]module.service["api"].local_file.manifest: Creation complete after 0s [id=7134233230fea48d7f78bb41fd0a9f3999c59b70] Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

On destroy, the order reverses: the files go before the pets.

Explicit dependencies

Sometimes a dependency is real but invisible in expressions:

resource "aws_iam_role_policy_attachment" "app_s3" {  role       = aws_iam_role.app.name  policy_arn = aws_iam_policy.read_reports.arn} resource "aws_instance" "app" {  ami                  = data.aws_ami.base.id  instance_type        = "t4g.small"  iam_instance_profile = aws_iam_instance_profile.app.name   # The app reads S3 at boot; the attachment is not referenced anywhere above.  depends_on = [aws_iam_role_policy_attachment.app_s3]}

The instance refers to the profile, which refers to the role, but nothing refers to the attachment. Without depends_on, the instance may boot before its permissions exist. Add a comment explaining why each depends_on is there; it is otherwise hard to tell a needed one from a superstitious one.

When the graph is wrong

  • Cycles: A refers to B and B refers to A, for example two security groups that each allow the other inline. Terraform reports Error: Cycle. Break it by using separate rule resources (aws_vpc_security_group_ingress_rule) that refer to both groups.
  • Eventual consistency: a resource is created, but the cloud API does not yet return it everywhere. Dependencies cannot fix that; providers usually retry, and sometimes a time_sleep is the honest fix.
  • Over-wide depends_on on modules or data sources defers reads to apply time and hides real changes behind (known after apply).

terraform graph prints the graph in DOT format if you ever need to see it.

2

Check yourself

3 questions. Get them all right to finish this topic.

  1. 1.A subnet block uses vpc_id = aws_vpc.main.id. What else do you need so the VPC is created first?
  2. 2.When is depends_on the right tool?
  3. 3.What is a cost of depends_on on a whole module?

0 of 3 right so far. Get all three to finish this topic.