Explore how Terramate can uplift your IaC projects with a free trial or personalized demo.
If you’ve ever tried to “make Terraform easy for developers,” you already know how this story goes.
You start with good intent: self-serve infrastructure, paved roads, and less ticket-driven ops. Then reality sets in. Every new team needs a slightly different variation. Every environment needs a slightly different exception. And suddenly, the IaC repositories - mission-critical codebases in the company - are slowly but surely spinning out of control.
This post is part of a short series on what makes Terramate Catalyst unique—and why we think it’s the new efficient frontier in Infrastructure as Code development.
If you are new to Terramate Catalyst, we recommend you read our post “A technical introduction to Terramate Catalyst.”
The core thesis for Terramate Catalyst
In most engineering organizations, only a few experts, such as platform and infrastructure teams, truly know how to deploy and manage production-grade infrastructure with IaC tools such as Terraform and OpenTofu in the right way.
This is because IaC is not accessible to most developers. You have to learn both HCL and the particulars of the cloud, which many developers simply don’t want to do - and they probably shouldn’t.
Instead of forcing Terraform upon the developers, the idea is to create a clear interface between what developers configure and what platform teams implement and control. So that the whole organization benefits from the experts’ capabilities.
IaC not accessible - what does that mean?
To use infrastructure, application developers need to know two things:
- Terraform / HCL
- How cloud infrastructure actually works
Terraform has a steep learning curve: HCL is yet another language to learn, and concepts like state, providers, and the plan/apply lifecycle introduce significant cognitive overhead.
The domain itself is just as complex, because the hardest part is understanding how clouds actually work:
- Choosing the right services and configuring them correctly
- Ensuring secure-by-default setups (networking, IAM, encryption)
- Staying within cost and quota constraints
- Implementing reliable backups and recovery strategies
- Putting the right monitoring and alerting in place
The downstream symptoms are painfully predictable
If you’ve spent time in the Terraform ecosystem, you’ve seen the same complaints over and over:
Teams start with a clean setup. Then it grows. Then it turns into a mess of modules, wrappers, copy/paste sprawl, and siloed knowledge.
Fast forward a couple of years, and the situation probably looks like this:
- Creating new infrastructure takes days or weeks because standards are hard to follow or barely exist
- Simple configuration changes require code changes in many places, becoming ever harder to maintain
- Version management: Provider, Terraform Module, or Terraform/OpenTofu upgrades that ought to be simple are becoming ever more challenging to roll out.
- “Self-service,” while often requested and promised, still creates a lot of friction between teams
- Engineers get frustrated, burn out, and leave because the work stops being fun
Contemporary solutions - and why they still hurt
Platform teams have tried to solve this for years. The patterns are familiar. The failure modes are too.
Terraform modules: an abstraction that still requires in-depth Terraform expertise
Terraform modules are the default solution. And they work, until they don’t.
To use a module well, you need to know both the module and the underlying Terraform: the dreaded 200% problem. Experts don’t mind, but what about your developers?
The tradeoff shows up fast:
- If the module is opinionated, teams fight it and fork it.
- If the module is flexible, it becomes a kitchen sink of variables.
- If the module is shared across teams, every change becomes political.
And the worst part: consumers often don’t really know what’s inside. They call the module, get outputs, and hope the module author didn’t bake in a surprise.
Modules are a great way to reuse code. But they are not a great way to build an interface contract between teams.
Terragrunt: more power, more surface area
Terragrunt tries to fix the “module composition” problem. It helps with DRY, environment wiring, orchestration, and one-off scaffolding.
But it inherits all the modules’ tension - and adds its own layer of complexity.
You still end up with:
- inconsistencies across multiple repos
- implicit behavior that only the expert truly understands
- configuration logic that turns into a second programming language
- brittle coupling between “what teams want” and “what the platform allows”
It’s not separation. It’s more glue. And the application developers have to learn yet another new technology that still isn’t easily accessible.
Scaffolding Engines and IDPs: great on day 1, painful on day 200
Scaffolding template engines such as Cookiecutter or Backstage’s Software Templates look great in demos.
You generate a repo. You get a working baseline. Everyone’s happy.
Then day 2 happens:
- teams modify the generated code
- the template evolves
- drift becomes permanent
- upgrades and day 2 are tedious
Blueprints optimize for creation. Real platforms need to create and maintain.
Ultimately, this approach makes the platform team's job easier. But this only solves half of the problem. Developers are still exposed to generated Terraform that they need to master. And we are back to the challenges of a steep learning curve for developers.
A new approach: Bundles that separate configuration from code
Catalyst takes a different approach: Bundles, the unit of reuse for application developers.
The goal is to separate configuration (what developers select and provide) from code (what platform teams implement and own).
This isn’t “Terraform modules, but nicer.” It’s the missing layer: an interface contract between platform teams and developers. One that scales across teams, promotes changes safely through environments, and abstracts away technical complexity.
What “separation” looks like in practice
In a typical “Terraform module-based platform” (often called “Terraform Service Catalog”), the interface still leaks cloud and tooling complexity, pushing developers to reason about low-level resources instead of outcomes.
module "service" {
source = "git::ssh://git@github.com/acme/platform-modules.git//service?ref=v3.8.1"
name = "payments-api"
environment = "prod"
# Leaky abstraction: app teams now need platform knowledge
vpc_id = data.terraform_remote_state.network.outputs.vpc_id
private_subnet_ids = data.terraform_remote_state.network.outputs.private_subnet_ids
kms_key_arn = data.terraform_remote_state.security.outputs.kms_key_arn
log_retention_days = 30
# Every team asks for "just one more option"
enable_waf = true
waf_rule_set = "strict"
enable_private_link = true
tags = {
owner = "payments"
tier = "critical"
}
}This looks reusable. But it’s not a stable interface. It pushes platform decisions into every application repo:
- Which VPC are we allowed to use?
- What’s the right subnet strategy?
- What KMS key is compliant?
- What’s the correct log retention?
- Which options are mandatory vs optional?
- What happens when the platform changes the “right” answer?
Now multiply this across:
- 20 teams
- 4 environments
- 3 regions
- varying seniority levels
- multiple IaC repositories
You don’t get self-service. You get distributed platform engineering.
Compare this with the same module configured as a Catalyst Bundle.
apiVersion: terramate.io/cli/v1
kind: BundleInstance
metadata:
name: payments-api
uuid: d92dce73-dfdc-4b26-961c-470359b37f46
spec:
source: /bundles/acme.com/service/aws/v3.8.1
inputs: # App-facing inputs shared between environments
name: payments-api
# ...
# defaults are set by platform teams and
# immutable configuration is not exposed user facing
specs: # environment specific configurations
dev:
inputs: # Development inputs inheriting and overwriting base configuration
# ..
prd: # Production inputs inherting lower environments and base
inputs:
# ...Instead of complex HCL and configuration, developers get an intuitive, simple-to-use YAML that exposes only the configuration relevant to them. The rest was already pre-configured by the platform team.
Notice developers no longer need to think about where infrastructure code lives in the repo, how Terraform is bootstrapped, or which state backend and providers are configured. That’s all built in: platform teams define and enforce where stacks are scaffolded in the filesystem, how remote state is set up, and which safe defaults apply — like Terraform, provider, state backend, and module versions.
Bundles can also include an upgrade path. When a new bundle version introduces additional infrastructure or configuration, Catalyst can automatically reconcile those changes. The result: developers don’t get pulled into complex day-2 operations — or forced to manually wrangle major module upgrades the way they often do with Terraform alone.
Benefits to both Developers & Platform Teams
This creates a true win-win: platform teams get the control and consistency they need, while developers get a workflow that’s easy to use — so they can ship faster without compromise.
For developers: the way of least resistance becomes the right way
When configuration is decoupled from code, the developer experience improves immediately:
- Fewer decisions to make — less complexity, faster provisioning
- No need to learn cloud internals just to ship infrastructure
- Guardrails by default, so teams can’t accidentally cause vulnerability via misconfigurations
- Faster onboarding for non-experts
- A clearer golden path that still feels flexible, not restrictive
Developers become productive by following the path of least resistance. And taking this path is equivalent to doing infrastructure “the right way”.
For platform teams: control without becoming the bottleneck
For platform teams, the biggest win is that both Day 1 & Day 2 improve.
Day 1: You can offer standardized, stable interfaces that encapsulate all your expertise in security, governance, & compliance.
Day 2: You can change what is underneath without affecting the developers. The interface stays the same, while you can do critical upgrades and maintenance in a decoupled fashion.
Bundles unlock “fleet management” for infrastructure:
- upgrades are centralized
- refactors don’t require rewriting every consumer repo
- policy changes can be enforced without waiting on every team
- reuse becomes real, not aspirational
- drift becomes manageable because the implementation stays owned
And because Bundles integrate cleanly into diverse toolchains — including IDPs — you don’t need to rebuild your platform stack around them.
Catalyst doesn’t try to replace your toolchain. It complements it.
The outcome
Effortless infrastructure that is governed, compliant, & secure by default.
And a stable contract between teams that thrive together.
So do give it a try. We’d love to hear what you think.
)
)
)
)