Dependencies and Data Sources

How I learned to orchestrate infrastructure by understanding the invisible threads that connect everything


Table of Contents


Introduction: The Circular Dependency Nightmare

It was 11 PM on a Friday. I had been staring at this error for two hours:

"Circular dependency detected."

My infrastructure was simple: an application config that referenced a database config, and a database config that referenced the application config. Each needed information from the other.

Terraform refused to apply. It showed me a dependency graph that looked like an infinite loop. My resources were chasing each other's tails.

I tried everything:

  • Reordering resources (didn't matter)

  • Removing references (broke functionality)

  • Creating intermediate resources (made it worse)

Finally, at midnight, a senior engineer looked at my code.

"Your problem isn't the code," they said. "It's your mental model. You're thinking in terms of 'what depends on what' when you should be thinking in terms of 'what data flows where.'"

They showed me how to use data sources to read existing information without creating dependencies. They explained the difference between implicit and explicit dependencies. They taught me about lifecycle rules that break dependency chains.

In 30 minutes, they refactored my tangled mess into a clean, linear dependency graph.

That night changed how I think about infrastructure. Dependencies aren't just about order—they're about data flow, timing, and orchestration.

This article is everything I learned about managing dependencies in Terraform.


What Are Dependencies?

A dependency is when one resource must be created before another.

Simple Example

Dependency: local_file.config depends on random_integer.port

Why? The file needs the random port number that hasn't been generated yet.

The Dependency Challenge

Terraform must determine:

  1. What order to create resources

  2. Which resources can be created in parallel

  3. How to handle failures and retries

Dependency Types

spinner

Implicit Dependencies

Implicit dependencies are automatically detected by Terraform when you reference one resource in another.

Basic Implicit Dependency

Terraform knows:

  1. Create random_string.id first

  2. Then create local_file.config using the generated ID

Multiple Implicit Dependencies

Dependencies:

  • local_file.config depends on random_integer.port

  • local_file.config depends on random_string.secret

Creation order:

  1. random_integer.port and random_string.secret (parallel)

  2. local_file.config (after both complete)

Chained Dependencies

Dependency chain:

Module Output Dependencies

Terraform knows:

  1. Create all resources in module.database

  2. Get output module.database.host

  3. Create local_file.app_config


Explicit Dependencies

Explicit dependencies are manually specified when Terraform can't automatically detect the relationship.

When Implicit Isn't Enough

Sometimes resources depend on each other without referencing attributes:

Problem: No attribute reference, so no implicit dependency.


The depends_on Meta-Argument

The depends_on meta-argument creates explicit dependencies.

Basic Usage

Result: local_file.data won't be created until local_file.schema completes.

Multiple Dependencies

Creation order:

  1. config_1 and config_2 (parallel)

  2. deployment (after both complete)

Module Dependencies

Result: All networking resources complete before any application resources start.

depends_on with count/for_each

Result: All prerequisite files created before main file.

When to Use depends_on

Use depends_on when:

  • ✅ Resources depend on each other but don't reference attributes

  • ✅ You need to ensure specific ordering for operational reasons

  • ✅ External systems require specific creation order

  • ✅ Module must complete before another starts

Avoid depends_on when:

  • ❌ You can use attribute references (implicit is better)

  • ❌ You're just guessing at dependencies

  • ❌ You're trying to fix unrelated errors


Understanding Data Sources

Data sources read information from external systems without managing those resources.

Resource vs Data Source

Resource: Terraform creates and manages it

Data source: Terraform reads it but doesn't manage it

Why Data Sources?

Scenario: You need information about resources created outside Terraform.

Example:

Data Source Benefits

  1. Read external data: Access resources not managed by Terraform

  2. No dependencies created: Reading doesn't create resource dependencies

  3. Always fresh: Data sources refresh on every plan/apply

  4. Separation of concerns: Different teams manage different resources


Using Data Sources

Local File Data Source

Read existing file:

Template File Data Source

Render template:

External Data Source

Run external program:

git-info.sh:

HTTP Data Source

Fetch from URL:

Data Source with Dependencies

Data sources can depend on resources:


Remote State Data Sources

Read outputs from another Terraform state.

Why Remote State Data Sources?

Scenario: Infrastructure split across multiple Terraform projects.

Project 1 (Networking):

Project 2 (Application):

Remote State with S3 Backend

Remote State Best Practices

1. Explicit outputs:

2. Stable interfaces: Don't change output names—dependent projects rely on them!

3. Documentation: Document what outputs are available and their purpose.


Dependency Graph

Terraform builds a dependency graph to determine creation order.

Visualizing Dependencies

Requires: graphviz package

Simple Graph Example

Configuration:

Graph:

spinner

Complex Graph

Configuration:

Graph:

spinner

Execution order:

  1. random_integer.port and random_string.secret (parallel)

  2. local_file.app_config and local_file.db_config (parallel, after step 1)

  3. local_file.main_config (after step 2)

Analyzing the Graph


Lifecycle Meta-Arguments and Dependencies

Lifecycle meta-arguments affect how dependencies work.

create_before_destroy

Default behavior: Destroy old, then create new

Problem: Can cause downtime

Solution:

Result:

  1. Create new app.conf (with different ID)

  2. Update references to point to new file

  3. Destroy old app.conf

prevent_destroy

Prevent accidental deletion:

Attempting to destroy:

Error:

ignore_changes

Ignore specific attribute changes:

Use case: Resource modified by external systems

replace_triggered_by

Replace when related resource changes:

Result: File replaced every time version changes


Module Dependencies

Modules can depend on other modules.

Implicit Module Dependencies

Explicit Module Dependencies

When to use:

  • Database must be fully initialized before app starts

  • Network infrastructure must exist first

  • Secrets must be created before services

Module Output Dependencies

Networking module:

Application module:


Common Dependency Patterns

Pattern 1: Sequential Creation

Pattern 2: Fan-Out

Graph:

spinner

Pattern 3: Fan-In

Graph:

spinner

Pattern 4: Diamond Dependency

Graph:

spinner

Real-World Example: Multi-Tier Application with Dependencies

Complete example showing all dependency concepts.

Project Structure

Database Module

modules/database/variables.tf:

modules/database/main.tf:

modules/database/outputs.tf:

Application Module

modules/application/variables.tf:

modules/application/main.tf:

modules/application/outputs.tf:

Monitoring Module

modules/monitoring/variables.tf:

modules/monitoring/main.tf:

modules/monitoring/outputs.tf:

Root Module

data.tf:

variables.tf:

main.tf:

outputs.tf:

Dependency Graph

spinner

Supporting Files

VERSION:

environments/production.yaml:

Deploy

Result:

  • ✅ Database created first

  • ✅ Applications created in parallel (after database)

  • ✅ Monitoring created (after applications)

  • ✅ Deployment manifest created (after all modules)

  • ✅ README generated (after manifest)


Debugging Dependency Issues

Enable Debug Logging

Analyze Dependency Graph

List Resource Dependencies

Output includes dependencies:

Trace Execution Order

Shows sequential execution


Circular Dependencies

The nightmare scenario.

Example of Circular Dependency

Error:

Breaking Circular Dependencies

Solution 1: Remove one dependency

Solution 2: Use intermediate resource

Solution 3: Split into separate applies


Parallel Resource Creation

Terraform creates independent resources in parallel.

Default Parallelism

Adjust Parallelism

What Can Run in Parallel?

These can run in parallel:

These cannot (dependencies):


Best Practices

1. Prefer Implicit Dependencies

Good:

Avoid:

2. Use depends_on Sparingly

Only when you can't use attribute references.

3. Document Dependencies

4. Avoid Circular Dependencies

Design your infrastructure to have clear dependency direction.

5. Use Data Sources for External Resources

6. Visualize Dependencies

Review the graph regularly.

7. Test Dependency Order

Ensures resources are created in correct order.


What I Learned About Dependencies

1. Dependencies Are About Data Flow

Not just creation order. Resources depend on each other because they need data from each other.

Understanding data flow is key to understanding dependencies.

2. Implicit > Explicit

Terraform is smart. Let it detect dependencies automatically whenever possible.

Only use depends_on when you must.

3. Data Sources Break Dependency Chains

Reading external resources doesn't create dependencies the same way managing them does.

Use data sources to access existing resources without creating tight coupling.

4. Circular Dependencies Mean Design Problems

If you have circular dependencies, your infrastructure design needs refactoring.

Think about which resources truly depend on which.

5. The Graph Is Your Map

The dependency graph shows the truth about your infrastructure relationships.

Visualize it. Study it. Learn from it.

6. Modules Are Dependency Boundaries

Modules help organize dependencies into logical groups.

Clear module interfaces (inputs/outputs) make dependencies explicit.


Next Steps

Congratulations! You've mastered dependencies and data sources:

✅ Implicit vs explicit dependencies ✅ The depends_on meta-argument ✅ Data sources for external data ✅ Remote state data sources ✅ Dependency graphs ✅ Lifecycle rules ✅ Module dependencies ✅ Common patterns ✅ Multi-tier application with complex dependencies ✅ Debugging and troubleshooting

Practice Exercises

Exercise 1: Dependency Analysis

Exercise 2: Data Sources

Exercise 3: Multi-Module Architecture

Coming Up Next

In Article 8: Testing Terraform - Validation, Testing, and Quality Assurance, we'll explore:

  • Input validation

  • terraform validate

  • terraform fmt and linting

  • Testing frameworks (Terratest, kitchen-terraform)

  • Integration testing

  • Policy as code (OPA, Sentinel)

  • CI/CD for Terraform

Dependencies connect your infrastructure. Testing ensures it works correctly.


This Week's Challenge: Map out all dependencies in your current infrastructure. Visualize the graph. Find opportunities to simplify using data sources or better module design.

See you in Article 8! 🔗


"The day I understood dependency graphs was the day circular dependencies stopped haunting me. Infrastructure isn't just code—it's relationships, data flow, and orchestration." - Me, after finally understanding the graph

Last updated