🧱 Modular Terraform Changed the Game for My AWS Setup

Deepak KumarDeepak Kumar
4 min read

A beginner’s journey from messy .tf files to reusable, production-grade infrastructure


🚀 Intro – From Working to Maintainable

When I began deploying my Drupal application on AWS using Terraform, I wasn’t thinking about code structure. I just wanted to get it working — and I did.

But as my infrastructure grew — with ECS, RDS, ALB, and now EFS — things started to break. My main.tf turned into a spaghetti bowl of AWS resources, hardcoded values, and copy-pasted blocks.

That’s when I paused, learned about Terraform modules, and refactored everything.

In this article, I’ll share why modular Terraform isn’t just “nice to have” — it’s essential for anyone building real-world infrastructure.


😵 What My Terraform Setup Looked Like Before

When I first set up my Terraform project, I followed what many beginners do — throw everything into a single directory:

terraform/
├\2500─ main.tf
├\2500─ variables.tf
└\2500─ outputs.tf

It started with a simple ECS task. Then came the cluster, the ALB, the RDS database, the security groups… all jammed into the same files.

At first, it worked. But soon I ran into serious issues:


❌ 1. Everything was tangled together

I had to scroll through hundreds of lines to find and edit anything. One tiny change in the security group could break the ECS config because it was all mixed.


❌ 2. Copy-paste ruled the repo

Whenever I needed a new resource — another SG, subnet, IAM policy — I’d copy an existing block and tweak it. This made the code repetitive and fragile.


❌ 3. Hardcoded values everywhere

Subnets, region names, AMIs, even account IDs were hardcoded. Switching regions or accounts would mean rewriting most of the code.


❌ 4. No separation of concern

If I wanted to destroy just RDS or just reconfigure ECS, I couldn’t. Everything was coupled tightly, so I was stuck with all-or-nothing changes.


My Terraform setup technically worked, but it wasn’t scalable, readable, or safe. I needed something better.


🧩 Why Modular Terraform Matters

That’s when I discovered modular Terraform — a way to break your infrastructure into clean, reusable blocks of code.

At a high level, here’s what modules gave me:


✅ Separation of concerns

Each module focuses on a single part of my setup — network, ecs, rds, efs, etc. No more tangled resource definitions.


✅ Reusability

I can now reuse the same ecs/ module for other services or projects. It’s just a matter of changing the input variables.


✅ Cleaner organization

Terraform feels like programming again. Each folder is like a class or function. Easier to read, debug, and maintain.


✅ Safer changes

If I change only the ecs module, I know it won’t affect RDS or VPC unintentionally. This gives me the confidence to experiment and scale.


📁 How I Structured My Project

Here’s how I reorganized my Terraform codebase into modules:

terraform/
├── network/
│   ├── main.tf
│   ├── outputs.tf
│   └── variables.tf
├── ecs/
│   ├── ecs_service.tf
│   ├── outputs.tf
│   └── variables.tf
├── rds/
│   ├── main.tf
│   ├── outputs.tf
│   └── variables.tf
├── efs/     # coming soon
├── iam/
│   └── main.tf
├── root main.tf (entry point)

Now, instead of a single giant main.tf, my root config calls each module with only the necessary variables.


🔗 Connecting Modules Without Hardcoding

This was another game-changer.

To connect resources across modules (e.g., VPC → ECS), I use:


🧠 1. terraform_remote_state

This lets me access outputs from other modules without hardcoding IDs.

data "terraform_remote_state" "network" {
  backend = "s3"
  config = {
    bucket = "my-tf-state-bucket"
    key    = "network/terraform.tfstate"
    region = "ap-south-1"
  }
}

🔍 2. Terraform data sources

For example, to get the current AWS Account ID and avoid hardcoding:

data "aws_caller_identity" "current" {}

output "account_id" {
  value = data.aws_caller_identity.current.account_id
}

These tricks make the setup flexible and safer across regions, environments, and teams.


🧠 What I Learned (So Far)

If you’re still writing Terraform in one big file or copy-pasting code, here’s my advice:

  • Start small, but modularize early
    It’s easier to break it down now than later

  • Avoid hardcoding
    Use data sources and remote state wherever possible

  • Think of Terraform like code
    Would you write your entire app in one function? No — treat infrastructure the same

  • Don’t fear remote state
    It feels scary at first, but it’s essential for cross-module communication


🔮 What’s Next?

I’m currently working on integrating EFS (Elastic File System) to persist Drupal’s file uploads and settings across ECS task restarts. That will fix the annoying issue where the Drupal install screen keeps reappearing.

Stay tuned — my next article will cover that journey and how I finally made my containers stateful where it mattered.


📝 Summary

I went from a giant main.tf file to a clean, modular Terraform setup.
It made my AWS infrastructure easier to read, reuse, and scale.

If your infra is growing and your Terraform is breaking — go modular before you go mad.


📇 Want to See the Code?

I’ve pushed my AWS setup to GitHub here:
🔗 github.com/deepakaryan1988/Drupal-AWS

0
Subscribe to my newsletter

Read articles from Deepak Kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Deepak Kumar
Deepak Kumar