Stop Building Terraform God Modules
Why modules with 40 inputs and passthrough variables slow teams down—and how to design reusable building blocks instead.
Gabriel Levasseur
Founder
Stop Building Terraform God Modules
Every platform team inherits at least one "god module"—a single module that promises to spin up the VPC, networking, security groups, cluster, autoscaling, logging, and dashboards all at once. It ships with pages of inputs to toggle features, plus passthrough variables for every nested resource. Consumers end up pasting whole sub-resource configs just to get a simple service out the door. The result? Nobody knows which inputs are required, drift sneaks in, and the module becomes a liability.
Recognize the god-module pattern
- Feature flag soup: A forest of booleans such as
enable_alb,enable_autoscaling, orcreate_private_dns. Turning one on silently creates other resources. - Config passthroughs: Catch-all objects like
security_group_configortask_definition_configthat demand full AWS argument maps. - Memory-only defaults: Inputs with
nulldefaults that force callers to discover intent by reading the internals. - Slow, scary plans: Terraform redraws half your infrastructure when a single toggle flips because the module has no clear boundaries.
Why it hurts consumers
God modules are hard to document, test, and reason about. Callers can't tell which combinations of flags are safe, so they cargo-cult the last working config. Reviewers can't confidently approve changes because every plan touches critical infrastructure. The platform team becomes the support desk for deciphering dozens of optional arguments.
If a module requires callers to pass entire nested resource configs "just in case," it's not an abstraction—it's a thin wrapper over raw Terraform that hides where the risk lives.
When a monolith might be okay
The only time a large module works is when it is extremely opinionated: one workload, one golden path, and tight defaults the team won't override. You're effectively vendoring a platform feature, not shipping a building block. The moment consumers need switches and passthroughs, the abstraction starts to crumble.
Prefer composable building blocks
Instead of a single kitchen-sink module, think in terms of modules that represent concrete capabilities. For example:
ecs-servicefor the service definition and task scheduling.ecs-service-scalingfor autoscaling policies tied to CloudWatch metrics.albfor listeners, target groups, and security groups.private-dnsandpublic-dnsfor Route53 zones and records.
These modules snap together so teams can plug-and-play what they need. Need an internal batch worker? Skip the ALB module and attach only scaling plus private DNS. Launching a public API? Compose the ALB and public DNS modules. Each piece remains testable, documented, and owned by the team closest to the concern.
How to unwind the monolith
- Inventory usage: Use
terraform-config-inspector repo search to list every caller and the inputs they set. - Slice by intent: Group inputs into concerns—networking, compute, observability—and define a module per intent.
- Codify defaults: Bake the platform's guardrails (encryption, logging, tagging) into each module so callers get them without extra flags.
- Expose escape hatches through composition: Offer extension points such as attaching additional security groups or extra listeners via module outputs, not extra booleans on the base module.
Document and test each slice
Publish an examples/ folder for each module and run them in CI (Terratest or terraform test). Consumers get copy-pastable patterns, and you gain confidence that the modules compose without surprises.
By retiring god modules, your Terraform library becomes easier to reason about. Engineers grab the building blocks that fit their intent, and platform teams evolve smaller, purpose-built components. Cora's graph view will reflect that clarity immediately—modular infrastructure turns sprawling spaghetti into concise, understandable architecture.
Audit your modules with Cora
Ready to see Cora in action? Jump into the product experience tailored to this article.
Audit your modules with CoraKeep reading
View allTerraform Complex Data Structures Are a Smell—Use Modules Instead
Why giant JSON inputs plus `for_each` loops hurt teams, and how to replace them with composable Terraform modules.
Gabriel Levasseur
Founder
Design Terraform Modules for the Right Consumer
Avoid fake abstractions by tailoring modules to the engineers who actually use them—and handling edge cases the right way.
Gabriel Levasseur
Founder
Cora Fall 2025 Roadmap: What's Shipping Next
How we're building the definitive Terraform visualization platform, from blast radius analysis to compliance dashboards and beyond.
Gabriel Levasseur
Founder