Terraform Depends On and Resource Dependencies
Infrastructure components often depend on each other. A web server cannot join a network that does not exist yet. A database cannot receive connections before its security group is configured. Terraform manages this through dependencies — both automatic and explicit. This topic explains how Terraform determines order and when you need to step in manually.
Why Order Matters
Cloud resources are not created in the order they appear in your files. Terraform builds a dependency graph and creates resources in parallel where possible — but it always respects dependencies to avoid errors.
Diagram: Deployment Order from Dependencies
What you want to create:
VPC → Subnet → Security Group → EC2 Instance → Elastic IP
Terraform dependency graph:
aws_vpc.main
|
v
aws_subnet.app -----> aws_security_group.web
|
v
aws_instance.server
|
v
aws_eip.server_ip
Terraform creates from top to bottom,
parallelising where branches allow.
Implicit Dependencies
When you reference one resource's attribute inside another resource, Terraform automatically detects the dependency. No extra code needed.
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "app" {
vpc_id = aws_vpc.main.id # <-- implicit dependency
cidr_block = "10.0.1.0/24"
}
Terraform sees that aws_subnet.app references aws_vpc.main.id. It creates the VPC first, then the subnet. You did not write any special ordering code — the reference itself declares the dependency.
Implicit dependencies cover the vast majority of real-world cases. Most of the time, you never need to think about order at all — it happens automatically from your attribute references.
Explicit Dependencies with depends_on
Sometimes one resource logically depends on another, but does not reference any of its attributes. Terraform cannot detect this dependency automatically. The depends_on meta-argument handles this case.
When Implicit Dependencies Are Not Enough
Imagine you create an IAM role and an S3 bucket. You then create an EC2 instance that will use that IAM role to read from that bucket. The instance references the role, so Terraform creates the role first. But the IAM policy attached to the role might not have propagated yet when the instance starts — IAM changes take a few seconds to become consistent across AWS.
resource "aws_iam_role" "app_role" {
name = "app-ec2-role"
# ... role configuration
}
resource "aws_iam_role_policy_attachment" "app_policy" {
role = aws_iam_role.app_role.name
policy_arn = "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"
}
resource "aws_instance" "app" {
ami = data.aws_ami.linux.id
instance_type = "t3.micro"
iam_instance_profile = aws_iam_instance_profile.app.name
depends_on = [aws_iam_role_policy_attachment.app_policy]
# Terraform waits for the policy attachment to complete
# before creating this instance
}
The instance already references aws_iam_instance_profile.app (implicit dependency on the profile). The depends_on adds an additional dependency on the policy attachment — ensuring the policy is attached before the instance starts, even though no attribute is directly referenced.
depends_on Syntax
resource "RESOURCE_TYPE" "NAME" {
# ... arguments
depends_on = [
resource_type.resource_name,
another_resource_type.another_name
]
}
depends_on accepts a list of resource references. It also works on modules:
module "app" {
source = "./modules/application"
depends_on = [module.networking]
}
Visualising Your Dependency Graph
Terraform can export its dependency graph in DOT format — a standard graph description language that graphing tools can render as a visual diagram.
terraform graph | dot -Tsvg > graph.svg
This command requires the graphviz tool installed separately. The resulting SVG shows every resource as a node and every dependency as a directed arrow — invaluable for understanding complex configurations.
Resource Creation and Destruction Order
Dependencies affect both creation and destruction order — but in opposite directions.
| Operation | Order |
|---|---|
| Create | Dependencies first, then dependents |
| Destroy | Dependents first, then dependencies |
If you destroy a stack, Terraform deletes the EC2 instance before the subnet, deletes the subnet before the VPC, and so on — always working backwards up the dependency chain.
Common Mistakes with Dependencies
- Circular dependencies: Resource A depends on B, and B depends on A. Terraform detects this and throws an error. Resolve by refactoring — often by extracting a shared resource that both A and B reference.
- Overusing depends_on: Adding
depends_onwhere an attribute reference already handles the dependency causes slower plans and unnecessary serialisation. Rely on implicit dependencies whenever possible.
Key Points
- Terraform builds a dependency graph and creates resources in dependency order — not file order.
- Implicit dependencies form automatically when you reference one resource's attribute inside another resource block.
- Use
depends_ononly when a dependency exists that Terraform cannot detect from attribute references alone. - Destruction order is the reverse of creation order — dependents are destroyed before their dependencies.
- Use
terraform graphto visualise the dependency graph of a complex configuration.
