Terraform Stacks: The Opinionated Deep Dive Nobody Warned You About

Terraform Stacks: The Opinionated Deep Dive Nobody Warned You About
Pull up a chair.
This is one of those topics where the official docs smile politely at you while quietly hiding the knife behind their back.
I’m going to be opinionated on purpose.
When people talk about Terraform stacks, the industry default still looks like this:
“Break everything into lots of small stacks (or workspaces), wire them together with remote state, and let teams own their little slice.”
It sounds mature. Scalable. Enterprise-ready.
I disagree.
Strongly.
I’ll argue that a single, orchestration-first stack with thin, boring modules is superior to the “many independent stacks stitched together with data sources” approach most teams adopt.
Terraform doesn’t force these architectural choices — it simply makes the consequences of poor boundaries impossible to ignore.

Two mental models. Only one tells the whole truth.
What a “stack” really is (not what the docs say)
Terraform doesn’t force these decisions. It simply refuses to hide their consequences. A Terraform stack is not a folder.
It’s not a workspace.
It’s not a module.
A stack is a decision boundary.
It defines:
what gets planned together
what gets applied together
what can fail together
what you mentally reason about at 2 a.m.
If that boundary is wrong, no amount of terraform fmt will save you.

A stack is where decisions, failure, and responsibility meet.
The industry standard: many small stacks
This is the popular model:
One stack for networking
One stack for IAM
One stack per service
One stack per environment
Remote state everywhere
On paper, it looks like microservices for infrastructure.
In practice?
It’s like running a restaurant where:
one team preps vegetables
another cooks
a third plates
a fourth serves
and none of them are allowed to talk directly
Everything goes through tickets.
You can run a kitchen like that.
You just won’t survive dinner rush.
The superior approach: orchestration-first stacks
Here’s the approach I recommend far more often than people expect:
One stack owns the lifecycle
Environment-level stack (dev, staging, prod)
It orchestrates everything that must change together
Modules are thin, dumb, and reusable
No cross-stack remote state for core dependencies
Think of it like a head chef.
The chef doesn’t chop every onion personally.
But they do decide:
when dishes go out
what gets cooked together
what happens when something is late
Terraform stacks should behave the same way.
Why this works better in the real world
Planning is where truth lives
Most infrastructure failures don’t happen at apply time.
They happen because the plan lied.
With many small stacks:
each plan is locally correct
the overall system is globally wrong
One stack. One plan. One truth.
If networking, compute, and permissions change together, you want to see the blast radius upfront.
Hiding it behind five pipelines doesn’t make it safer.
It makes it invisible.
Humans reason in stories, not graphs
Docs assume engineers think in dependency graphs.
They don’t.
They think in narratives:
“We’re adding a new service that needs a load balancer, IAM role, and database.”
That story fits naturally in a single orchestration stack.
Splitting it across stacks forces the reader to mentally replay a detective novel just to understand why an output exists.
If understanding your infra requires a whiteboard, your stack boundary is wrong.
Thin modules age better than clever stacks
People love clever modules.
They age like milk.
Thin modules:
create resources
accept primitives
return boring outputs
The intelligence belongs in the stack.
Business logic changes faster than infrastructure primitives.
Your stack is allowed to change.
Your modules should feel embarrassingly simple.
A real-world analogy: load balancing as a kitchen
Load balancing is often explained with diagrams.
Here’s a better analogy.
A busy restaurant doesn’t assign customers directly to chefs.
There’s a host.
The host:
sees the whole room
knows which tables are overloaded
adapts in real time
A single orchestration stack is that host.
Multiple disconnected stacks are customers wandering into the kitchen shouting orders and hoping someone listens.
“But what about team autonomy?”
This is where people get emotional.
They hear “single stack” and think:
“Centralized control. Bottlenecks. A platform team saying no.”
That’s not a stack problem.
That’s an ownership problem.
You can:
keep code ownership per module
enforce review boundaries
delegate responsibility
without fragmenting the lifecycle.
Autonomy without coordination is just chaos with better branding.
The Ugly Truth (the part many techies and contents avoid)
Let’s be honest.

*Terraform makes dependencies explicit — which means poor boundaries become visible faster. *
Single stacks have real downsides
Plans get big
Applies take longer
One mistake can block multiple teams
State files become precious artifacts
You will feel this pain.
But here’s the part people won’t say out loud:
You are already paying these costs.
You’re just paying them in outages, debugging time, and human stress instead of CI minutes.
Remote state is a powerful tool — but it doesn’t remove coupling, it postpones when you feel it.
When many stacks actually make sense
I’m not dogmatic.
Split stacks when:
lifecycles are genuinely independent
failure domains must be isolated
regulatory boundaries demand it
applies cannot safely happen together
If two things always change together, they belong together.
The mentor advice I wish I got earlier
Design Terraform stacks the way you’d design incident response.
Ask yourself:
“What do I want to see in one plan?”
“What should never drift independently?”
“What failure would wake me up at night?”
Then draw your boundaries there.
Not where the docs say.
Not where the trend points.
Where reality lives.
Author’s note: This post is intentionally opinionated and drawn from real production experience. It’s not a critique of Terraform as a tool, but of common patterns teams adopt without revisiting their trade-offs. Terraform is doing exactly what it’s designed to do — making dependencies and boundaries explicit. The goal here is to encourage more deliberate stack design, not prescribe a single “correct” way to use Terraform. Happy terraforming!
#terraform #hashicorp





