Terraform Mastery - Day 13: depends_on & Lifecycle in Terraform
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_onand when to use itLifecycle 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?
| Feature | Purpose | Example Use Case |
depends_on | Explicitly define dependencies | Ensure a database is created before an application server. |
lifecycle | Control creation, updates, or deletion | Prevent 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:
An RDS Database
An Application Server (EC2 instance)
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! 🚀