Skip to main content

Command Palette

Search for a command to run...

Terraform Mastery - Day 13: depends_on & Lifecycle in Terraform

Published
4 min read

Mastering Dependency Management and Resource Lifecycle in Terraform

Infrastructure as Code (IaC) is all about automation, but dependencies and resource lifecycle need careful handling to ensure seamless deployments. In Terraform, the depends_on argument and the lifecycle block help in controlling dependencies and defining how resources should be created, updated, or destroyed.

This blog will cover:

  • Terraform’s built-in dependency management

  • Understanding depends_on and when to use it

  • Lifecycle blocks and their usage

  • Best practices for handling dependencies and lifecycle policies

Let’s dive in! 🚀


1️⃣ Understanding Dependencies in Terraform

Terraform uses a dependency graph to determine the order in which resources should be provisioned. It automatically understands that a resource referenced inside another resource is a dependency.

Example of Implicit Dependency:

resource "aws_security_group" "example_sg" {
  name        = "example-sg"
  description = "Example Security Group"
}

resource "aws_instance" "example_instance" {
  ami           = "ami-0abcdef1234567890"
  instance_type = "t2.micro"
  security_groups = [aws_security_group.example_sg.name]  # Implicit dependency
}

📌 Here, Terraform knows that the EC2 instance depends on the Security Group because it is referenced in the security_groups attribute. Terraform will automatically provision the security group first.

However, sometimes Terraform does not detect dependencies properly. That’s where depends_on comes into play.


2️⃣ What is depends_on?

The depends_on argument explicitly tells Terraform that one resource should be created before another, even if Terraform doesn’t detect an implicit dependency.

🚀 Example: EC2 instance depends on an S3 bucket

resource "aws_s3_bucket" "my_bucket" {
  bucket = "my-app-bucket"
}

resource "aws_instance" "my_instance" {
  ami           = "ami-0abcdef1234567890"
  instance_type = "t2.micro"
  depends_on    = [aws_s3_bucket.my_bucket]  
}

📌 Why use depends_on here?
Even though the EC2 instance doesn’t directly reference the S3 bucket, we want to ensure the bucket exists before the instance is provisioned.


3️⃣ Lifecycle Blocks in Terraform

Terraform's lifecycle block provides fine-grained control over how resources should be created, updated, and destroyed.

Key lifecycle Arguments:

  • create_before_destroy: Ensures a new resource is created before destroying the old one.

  • prevent_destroy: Prevents accidental deletion of a critical resource.

  • ignore_changes: Prevents Terraform from modifying specific attributes of a resource.

🚀 Example: Preventing an S3 bucket from accidental deletion

resource "aws_s3_bucket" "my_bucket" {
  bucket = "my-important-bucket"

  lifecycle {
    prevent_destroy = true
  }
}

📌 Why? This ensures Terraform does not delete the bucket, preventing data loss.

🚀 Example: Ignoring specific changes

resource "aws_instance" "web" {
  ami           = "ami-0abcdef1234567890"
  instance_type = "t2.micro"

  lifecycle {
    ignore_changes = [ami]
  }
}

📌 Why? Even if the AMI ID changes in the configuration, Terraform will not update the instance, preventing unnecessary re-provisioning.


4️⃣ When to Use depends_on vs. Lifecycle?

FeaturePurposeExample Use Case
depends_onExplicitly define dependenciesEnsure a database is created before an application server.
lifecycleControl creation, updates, or deletionPrevent accidental deletion of an S3 bucket.

5️⃣ Best Practices for depends_on & Lifecycle

Avoid overusing depends_on – Terraform automatically detects most dependencies.
Use lifecycle policies to enforce infrastructure stability.
prevent_destroy for critical resources like databases, production S3 buckets, etc.
Use ignore_changes for externally managed attributes.


6️⃣ Real-World Use Case: Deploying a Web Application

Scenario:

You are deploying a web application that consists of:

  1. An RDS Database

  2. An Application Server (EC2 instance)

  3. An S3 Bucket for storing files

We need to ensure:
✅ The S3 bucket exists before the EC2 instance is deployed
✅ The database is created before the application tries to connect to it
✅ The S3 bucket is never deleted

Solution:

resource "aws_s3_bucket" "app_bucket" {
  bucket = "my-app-files"

  lifecycle {
    prevent_destroy = true
  }
}

resource "aws_db_instance" "app_db" {
  allocated_storage    = 20
  engine              = "mysql"
  instance_class      = "db.t2.micro"
  username           = "admin"
  password           = "mypassword"
}

resource "aws_instance" "app_server" {
  ami           = "ami-0abcdef1234567890"
  instance_type = "t2.micro"

  depends_on = [aws_db_instance.app_db, aws_s3_bucket.app_bucket]
}

📌 What happens here?
✅ The S3 bucket is created first
✅ The database is created next
✅ The application server is provisioned last, ensuring it connects to an existing DB


Final Thoughts

Terraform’s depends_on and lifecycle blocks provide powerful ways to manage infrastructure dependencies and stability. By understanding when and how to use them, you can create more reliable, efficient, and controlled Terraform deployments.

📢 What’s next? Tomorrow, we dive into Dynamic Blocks! 🚀