How to fix Dependency cycle detected in Terraform

TerraformINTERMEDIATEHIGHUpdated Dec 30, 2025· 140 views

Terraform detected a circular dependency in your infrastructure configuration where resources depend on each other directly or through a chain, preventing Terraform from determining creation order. Break the cycle by refactoring resource relationships or using intermediate resources.

Quick fix

Fixes Dependency cycle detected

Error: Cycle: aws_security_group.frontend -> aws_security_group.backend -> aws_security_group.frontend
  1. Identify resources in the cycle
  2. Examine resource references
  3. Break the cycle using separate resource blocks
  4. Use data sources instead of direct references
terraform — error
Error: Cycle: aws_security_group.frontend -> aws_security_group.backend -> aws_security_group.frontend
Dependency cycle detected

What this error means

A dependency cycle occurs when Terraform detects that Resource A depends on Resource B, but Resource B also depends on Resource A (directly or indirectly through other resources). This creates an impossible situation where Terraform cannot determine which resource to create first. The error prevents any infrastructure changes from being applied because the dependency graph has no valid starting point.

Typical symptoms

  • Terraform plan or apply fails with 'Dependency cycle detected' error
  • Error message references specific resource types in the cycle
  • terraform plan shows no actionable items and exits with error
  • Changes cannot be applied even though configuration appears valid
  • Error occurs when running terraform init, plan, or apply

Common causes

  1. Two security groups referencing each other in ingress/egress rules
  2. A load balancer security group that references the target group's security group, which references back
  3. IAM roles that depend on policies while the policies depend on the role for permissions
  4. Module outputs feeding back into module inputs that are required for the module itself
  5. VPC resources referencing each other (route tables, network interfaces, subnets)
  6. Direct resource-to-resource attribute references creating implicit dependencies
  7. Misuse of depends_on argument creating unnecessary explicit cycles

How to fix "Dependency cycle detected"

1Identify resources in the cycle

Read the error message carefully. Terraform usually shows which resource type is involved in the cycle:

bash
Error: Cycle: aws_security_group.frontend -> aws_security_group.backend -> aws_security_group.frontend

Note the resource types and logical names. Run terraform graph | grep -E "(cycle|frontend|backend)" to visualize relationships if available.

2Examine resource references

Open your Terraform configuration files and find where these resources reference each other. Look for:

- Direct attribute references: aws_security_group.backend.id
- Implicit depends_on (via references)
- Explicit depends_on arguments

Example problematic code:

hcl
resource "aws_security_group" "frontend" {
  ingress {
    from_port       = 443
    to_port         = 443
    security_groups = [aws_security_group.backend.id]  # References backend
  }
}

resource "aws_security_group" "backend" {
  ingress {
    from_port       = 3306
    to_port         = 3306
    security_groups = [aws_security_group.frontend.id]  # References frontend - CYCLE!
  }
}
3Break the cycle using separate resource blocks

Instead of defining ingress rules inline within security group resources, use separate aws_security_group_rule resources. This lets Terraform create both groups first without dependencies:

hcl
resource "aws_security_group" "frontend" {
  name = "frontend"
  # Removed ingress block
}

resource "aws_security_group" "backend" {
  name = "backend"
  # Removed ingress block
}

# Now define rules separately - no cycle
resource "aws_security_group_rule" "frontend_to_backend" {
  type              = "ingress"
  from_port         = 3306
  to_port           = 3306
  protocol          = "tcp"
  security_group_id = aws_security_group.backend.id
  source_security_group_id = aws_security_group.frontend.id
}

resource "aws_security_group_rule" "backend_to_frontend" {
  type              = "ingress"
  from_port         = 443
  to_port           = 443
  protocol          = "tcp"
  security_group_id = aws_security_group.frontend.id
  source_security_group_id = aws_security_group.backend.id
}
4Use data sources instead of direct references

For external resources you don't manage in this configuration, use data sources instead of creating new resources:

hcl
# Bad - creates implicit dependency
resource "aws_security_group_rule" "example" {
  security_group_id = aws_security_group.mine.id
  source_security_group_id = aws_security_group.existing.id  # May not exist yet
}

# Good - fetches existing resource without creating dependency
data "aws_security_group" "existing" {
  name = "existing-group-name"
}

resource "aws_security_group_rule" "example" {
  security_group_id = aws_security_group.mine.id
  source_security_group_id = data.aws_security_group.existing.id  # No cycle
}
5Refactor modules to remove circular module dependencies

If the cycle is between modules, restructure them:

hcl
# Module A depends on B, Module B depends on A = CYCLE

# Solution: Extract common outputs to a separate module
module "networking" {
  source = "./modules/networking"
  # Both A and B depend on this
}

module "database" {
  source = "./modules/database"
  vpc_id = module.networking.vpc_id  # Depends on networking
}

module "api" {
  source = "./modules/api"
  vpc_id = module.networking.vpc_id         # Depends on networking
  db_endpoint = module.database.endpoint    # Depends on database
}
6Use locals to break reference cycles

Create local values that both resources can reference instead of referencing each other:

hcl
locals {
  backend_port = 3306
  frontend_port = 443
}

resource "aws_security_group" "frontend" {
  ingress {
    from_port   = local.frontend_port
    to_port     = local.frontend_port
    protocol    = "tcp"
    cidr_blocks = ["10.0.0.0/8"]
  }
}

resource "aws_security_group" "backend" {
  ingress {
    from_port   = local.backend_port
    to_port     = local.backend_port
    protocol    = "tcp"
    cidr_blocks = ["10.0.0.0/8"]
  }
}
7Verify the fix with terraform plan

After refactoring, test the configuration:

bash
terraform init
terraform plan

Verify that:
- No cycle errors appear
- All resources show creation/modification as expected
- Dependency graph makes sense (use terraform graph if needed)

If cycles remain, repeat steps 1-2 to identify additional cycles.

Advanced notes

Advanced cycle detection patterns:

Implicit vs Explicit Dependencies: Most cycles come from implicit dependencies (attribute references). Explicit depends_on should only be used when Terraform cannot infer a dependency automatically. Never use depends_on to fix cycles—it will only mask the problem.

Multi-level cycles: Sometimes cycles span 3+ resources (A->B->C->A). Use terraform graph command to visualize: terraform graph | dot -Tsvg > graph.svg (requires Graphviz).

Provider configuration cycles: If a provider's configuration references resources it manages, this creates a bootstrap problem. Solution: Use separate provider blocks or move the resource outside the managed infrastructure.

Terraform Cloud/Enterprise: Cycles can also occur when variable dependencies are misconfigured in sentinel policies or run triggers.

Prevention: Design infrastructure with clear hierarchical dependencies. Use modules to organize resources by concern (networking, compute, data). Always review terraform plan output before applying.

Frequently asked questions

What does "Dependency cycle detected" mean?
A dependency cycle occurs when Terraform detects that Resource A depends on Resource B, but Resource B also depends on Resource A (directly or indirectly through other resources). This creates an impossible situation where Terraform cannot determine which resource to create first. The error prevents any infrastructure changes from being applied because the dependency graph has no valid starting point.
How do I fix "Dependency cycle detected"?
Terraform detected a circular dependency in your infrastructure configuration where resources depend on each other directly or through a chain, preventing Terraform from determining creation order. Break the cycle by refactoring resource relationships or using intermediate resources.
What causes "Dependency cycle detected"?
Two security groups referencing each other in ingress/egress rules A load balancer security group that references the target group's security group, which references back IAM roles that depend on policies while the policies depend on the role for permissions
Is the "Dependency cycle detected" error serious?
Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.

Official resources & further reading