Skip to main content

Managing Dependencies

1. Using Implicit Dependencies

Dependency Type Description Usage Notes
data source Fetches external data for use in configuration data "aws_ami" "latest" { filter { name = "name" values = ["ubuntu/images/ubuntu-20.04/*"] } } Used to reference data not managed by Terraform
resource reference References output from another resource output "instance_ip" { value = aws_instance.web.private_ip } Implicitly creates dependency between resources
module output Exports values from a module for use in parent configurations output "vpc_id" { value = module.vpc.vpc_id } Enables modular composition and reuse

Example: Implicit dependency via resource reference

resource "aws_security_group" "allow_ssh" {
  name        = "allow_ssh"
  description = "Allow SSH inbound traffic"
  vpc_id      = aws_vpc.main.id
}

resource "aws_instance" "web" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t2.micro"
  security_groups = [aws_security_group.allow_ssh.name]
}
Note: Terraform automatically detects and manages dependencies based on resource references in configurations.
Warning: Avoid circular dependencies between resources or modules.

2. Using Explicit Dependencies

Property Description Example
source Specifies the location of the module source = "terraform-aws-modules/vpc/aws"
version Version constraint for the module version = "~> 3.0"

Example: Module with Explicit Dependencies

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 3.0"

  name = "my-vpc"
  cidr = "10.0.0.0/16"
}
Note: Explicit dependencies ensure reproducible infrastructure by locking to specific versions.

3. Understanding Dependency Graph

Resource Dependencies Description
aws_instance.web aws_security_group.web Web instance depends on security group for network access
aws_elb.web aws_instance.web Load balancer depends on web instances for routing
aws_route53_record.www aws_elb.web DNS record depends on ELB for domain resolution
Note: Terraform automatically builds a dependency graph based on resource references in configuration files.

Example: Explicit Dependency Declaration

resource "aws_instance" "web" {
  ami           = "ami-12345678"
  instance_type = "t2.micro"
}

resource "aws_instance" "db" {
  ami           = "ami-87654321"
  instance_type = "t2.micro"

  depends_on = [aws_instance.web]
}

Dependency Resolution Workflow

  1. Parse all resource definitions
  2. Identify references between resources
  3. Build dependency graph using depends_on and implicit references
  4. Sort resources for creation/destruction in dependency order

4. Visualizing Dependencies

Example: Dependency Graph with terraform graph

terraform graph
Command Description Output Format
terraform graph Generates a visual representation of the dependency graph Graphviz DOT format
terraform graph -draw-cycles Includes cycle detection in the graph Graphviz DOT format with cycles marked
Note: The output is in Graphviz DOT format. To visualize it, you can pipe the output to dot or use tools like Graphviz Online.

Example: Exporting Graph to PNG

terraform graph | dot -Tpng -o dependencies.png

Key Features of Dependency Visualization

  • Shows resource dependencies in a visual graph
  • Helps identify circular dependencies
  • Supports export to various formats (PNG, SVG)

5. Handling Circular Dependencies

Note: Terraform does not support circular dependencies between modules or resources. If a circular dependency is detected, Terraform will return an error during validation.
Dependency Type Description Impact Solution
Module Dependency When Module A depends on Module B, and Module B also depends on Module A Causes validation error during terraform plan Refactor modules to remove circular reference
Resource Dependency When Resource A depends on Resource B, and Resource B also depends on Resource A Causes validation error during terraform plan Reorganize resource definitions to eliminate circular reference

Example: Circular Module Dependency

# module_a/main.tf
module "module_b" {
  source = "./module_b"
}

# module_b/main.tf
module "module_a" {
  source = "./module_a"
}

Workflow to Resolve Circular Dependencies

  1. Identify the circular dependency in terraform plan output
  2. Refactor modules to remove direct dependencies between them
  3. Use data sources or outputs to pass information between modules
  4. Validate changes with terraform plan

Best Practices to Avoid Circular Dependencies

  • Design modules with clear input/output boundaries
  • Avoid direct dependencies between modules in a circular pattern
  • Use data sources to fetch information from other modules instead of direct dependencies
  • Use terraform graph to visualize module and resource dependencies

6. Using Module Dependencies

Property Description Example
source Location of the module, can be local path, Git repo, or registry source = "terraform-aws-modules/vpc/aws"
version Version constraint for the module version = "~> 3.0"

Example: Using a Module from the Registry

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 3.0"

  name = "my-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["us-east-1a", "us-east-1b", "us-east-1c"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  public_subnets  = ["10.0.10.0/24", "10.0.11.0/24", "10.0.12.0/24"]
}

Example: Using a Local Module

module "database" {
  source = "../modules/database"

  engine         = "postgres"
  instance_class = "db.t3.micro"
}
Note: Module dependencies are resolved during terraform init. Ensure that the module source is accessible and compatible with your Terraform version.

7. Managing Provider Dependencies

Property Description Example
provider Defines a Terraform provider to be used in the configuration
provider "aws" {
  region = "us-west-2"
}
version Specifies the version of the provider to use
provider "aws" {
  region = "us-west-2"
  version = "~> 5.0"
}
alias Allows multiple configurations of the same provider
provider "aws" {
  alias = "us_west"
  region = "us-west-2"
}

Example: Using provider version constraints

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}
Note: Use ~> for version constraints to allow minor updates while preventing major breaking changes.

Example: Using multiple provider configurations

provider "aws" {
  region = "us-west-2"
}

provider "aws" {
  alias  = "east"
  region = "us-east-1"
}

resource "aws_instance" "web" {
  provider = aws
  # ...
}

resource "aws_instance" "db" {
  provider = aws.east
  # ...
}

8. Ordering Resource Creation

Option Values Notes
depends_on list(resource) Explicitly define resource dependencies
lifecycle precondition, postcondition Enforce conditions before/after resource creation

Example: Using depends_on

resource "aws_instance" "web" {
  depends_on = [aws_instance.db]
  # ...
}

resource "aws_instance" "db" {
  # ...
}

Example: Using lifecycle preconditions

resource "aws_s3_bucket" "example" {
  lifecycle {
    precondition {
      condition = length(self.bucket) > 0
      error_message = "Bucket name must not be empty"
    }
  }
}

9. Using Data Source Dependencies

Property Description Example
data.<type>.<name> Defines a data source in Terraform data.aws_ami.ubuntu
depends_on Ensures data source is created after other resources depends_on = [aws_instance.web]

Example: Fetching AMI ID from AWS

data "aws_ami" "ubuntu" {
  most_recent = true
  owners      = ["099720109477"]
  filters {
    name   = "ubuntu/images/ubuntu-core-20.04-latest-amd64"
  }
}

Example: Using Data Source in Resource

resource "aws_instance" "web" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t2.micro"
}
Note: Data sources are read-only and do not create infrastructure.

10. Debugging Dependency Issues

Issue Description Solution
Provider version conflicts Multiple modules or configurations require different versions of the same provider. Use required_providers with specific version constraints to resolve conflicts.
Module not found Terraform cannot locate a module specified in source. Verify the module path, check for typos, and ensure the module is accessible (e.g., via Git or registry).
State file corruption State file is invalid or corrupted, causing errors during apply. Use terraform state pull to inspect and potentially restore from backup or reinitialize.
Resource drift Actual infrastructure differs from Terraform state. Use terraform plan to identify drift and terraform import to reconcile.

Example: Resolving Provider Version Conflicts

terraform {
  required_version = ">= 1.0"
}

required_providers {
  aws = {
    source  = "hashicorp/aws"
    version = "~> 5.0"
  }
}
Note: Use terraform providers to inspect the resolved provider versions in your configuration.
Warning: Avoid using = "*" in provider versions as it can lead to unexpected upgrades.

Was this article helpful?