Terraform’s Dominance Is Slipping and Pulumi Knows Why

For years, Terraform rode a wave of “configuration as truth”: describe the desired state in HCL, let the engine reconcile reality, and move on. It worked—because the industry needed standardization more than it needed elegance. But as teams matured, a different problem emerged: infrastructure isn’t just configuration. It’s software. And that’s exactly where Pulumi starts to win.
HCL Solved a Problem—Then Developers Hit the Wall⌗
HCL is a reasonable idea. Terraform’s declarative model, and its promise that you can model infrastructure resources in a dedicated language, made it approachable and portable. When you’re wiring up a few services, modules feel clean, state management is predictable, and the learning curve is manageable.
The wall comes when the infrastructure complexity stops being “a bunch of resources” and becomes “a system with behavior.”
Real teams don’t build static stacks. They build conditional deployments (prod vs. staging), multi-tenant environments, environment-dependent naming rules, conditional networking, and resource graphs that vary depending on runtime inputs. In Terraform, this logic exists—but it’s awkward. You end up encoding software patterns using a declarative toolchain with:
- Expressions that get hard to read and debug
- Repeated “plumbing” for maps, locals, and dynamic blocks
- Modules that grow into mini-programs with limited abstraction power
- Copy/paste patterns that resist refactoring because the language fights you
HCL isn’t wrong; it just isn’t optimized for how developers naturally reason. When your infrastructure begins to look like application code—because it effectively is application code—you feel the friction.
“Infrastructure as Configuration” Becomes a Productivity Tax⌗
Here’s the uncomfortable truth: infrastructure-as-configuration treats the most valuable part of modern engineering—iteration—as an afterthought.
Most engineering teams expect to do the following routinely:
- write small, testable units
- factor shared logic into reusable abstractions
- refactor safely with IDE support
- use existing language tooling for linting, formatting, and static analysis
- apply conventional control flow patterns (loops, conditionals, early returns)
Terraform can do some of this, but it doesn’t do it in the way software engineers expect. Instead, you’re limited to the constructs Terraform provides, and “logic” often becomes data transformation inside expressions. That can be fine until you need robust branching, non-trivial orchestration, or you just want the simplest possible way to validate inputs and invariants.
Practical example: multi-tenant provisioning
Imagine a platform that creates a network, deploys a database, and configures application access per tenant. Each tenant has features toggled based on a configuration file—some tenants need private endpoints, others don’t; some require extra security controls; others have simpler defaults.
In a configuration-first approach, you’ll represent this as deeply nested variables and conditionals. The resulting code becomes a maze of maps, merges, and dynamic blocks. Even if it’s correct today, future changes are expensive because the “program” isn’t truly a program—it’s a declaration expressed in a constrained DSL.
Once you feel that pain, the argument stops being philosophical. It becomes economic: time spent deciphering infrastructure code isn’t building value. It’s paying a tax.
Pulumi Treats Infrastructure Like Code—Because It Is⌗
Pulumi’s core bet is straightforward: define infrastructure in real programming languages—TypeScript, Python, Go, and others—so your infrastructure enjoys the full power of the software toolchain.
That means you get real loops, real conditionals, and real functions. But more importantly, you get structure. You can create abstractions that match how developers think rather than forcing everything through the grammar of HCL.
Consider the same multi-tenant scenario in a general-purpose language:
- You can model the tenant configuration as data structures.
- You can write a function that returns the desired resources for a tenant.
- You can reuse shared logic naturally.
- You can validate inputs early (before deployment) and fail fast.
Example (TypeScript-style pseudocode):
You might have a provisionTenant(tenantSpec) function that:
- computes naming and tags
- decides whether to attach private networking
- creates the database with the right configuration
- outputs connection details
- optionally enables extra security resources
That’s not just “easier.” It’s more maintainable. When the team grows, onboarding gets faster because infrastructure code reads like code. When requirements change, refactoring isn’t a gamble.
And because Pulumi supports unit testing around your infrastructure logic, you can test the behavior you care about. You’re no longer restricted to hoping a deployment succeeds as your primary validation strategy.
Tooling Compounds: Refactor, Test, and Review Faster⌗
The strongest argument for Pulumi isn’t that it can express infrastructure differently—it’s that it plugs into the development workflow teams already have.
When your infrastructure is written in a real language:
- IDE refactoring works. Rename a function or extract a module and trust your tooling to update call sites.
- Static analysis works. Catch obvious issues before you run CI/CD.
- Unit tests are possible. You can test logic that computes resource properties, naming conventions, and policy decisions.
- Code review becomes sharper. Reviewers can reason about control flow, helper functions, and invariants instead of parsing nested expressions.
This matters in practice because infrastructure failures are rarely “random.” They’re almost always caused by changes: new tenants, new regions, updated credentials, toggled features, or altered security requirements. If your infrastructure logic is difficult to validate locally, you end up moving mistakes downstream—into the apply step—where feedback is slower and the blast radius is larger.
Pulumi’s approach doesn’t eliminate the need for careful review and deployment discipline. It reduces the chance that you can’t even reason about the system you’re about to deploy.
Terraform’s Ecosystem Is Real—But Pulumi’s Model Is the Point⌗
Terraform’s ecosystem is undeniably large. There are countless modules, a huge base of existing knowledge, and mature patterns for state management and dependency graphs. For many teams, that ecosystem has been enough to justify the tradeoffs.
But the tradeoffs are why dominance is slipping.
When infrastructure engineering moves from “write once, deploy many” to “continuously evolve,” the ability to treat infrastructure as a maintainable software codebase becomes a strategic advantage. Pulumi’s promise isn’t only flexibility—it’s that your infrastructure code can be engineered like the rest of your systems.
And the market has been quietly acknowledging this. CDK for Terraform (CDKTF) is HashiCorp’s admission that HCL wasn’t enough for many developers. CDKTF lets you define Terraform configurations using a programming language and generates HCL under the hood. In other words: even Terraform is moving toward the “actual code” model because teams want familiar abstractions, reusable libraries, and real control flow.
That doesn’t mean HCL will disappear. It means the center of gravity is shifting. People want the Terraform engine and module ecosystem sometimes, but they increasingly want the developer experience benefits that come from writing infrastructure the way developers actually write software.
Choosing the Right Approach: A Practical Decision Checklist⌗
If you’re evaluating whether to adopt Pulumi (or whether to stick with Terraform), don’t get distracted by debates about “purity.” Use a checklist that reflects how your team builds.
Choose Pulumi if:
- Your infrastructure logic is already complex (conditional resources, multi-tenant patterns, environment-specific branching).
- You want to reuse abstractions and refactor confidently with IDE tooling.
- You would benefit from unit tests for infrastructure decisions (naming, policy enforcement, computed configuration).
- Your team is staffed by developers who expect real code workflows, not DSL workarounds.
Stick with Terraform if:
- Your organization relies heavily on existing HCL modules and workflows, and migration would be costly.
- Your deployments are mostly static and the declarative model stays readable.
- You prefer the current ecosystem’s module-driven development and your teams are already productive with it.
And here’s the compromise that often works: if you’re committed to Terraform but feel the pain of HCL logic, consider reducing logic density—push computation into fewer, cleaner modules, standardize naming and tagging, and aggressively document module contracts. If that still isn’t enough, Pulumi’s model may be the real fix.
Conclusion: Infrastructure Is Software—Stop Treating It Like Configuration⌗
Terraform’s HCL was a milestone: it made infrastructure approachable and standardized. But software teams didn’t stop at “approachable.” They kept building systems that behave, evolve, and grow. At that point, infrastructure isn’t configuration—it’s software engineering.
Pulumi wins because it aligns infrastructure with how developers actually work: real programming languages, real abstractions, unit-testable logic, and refactoring support that doesn’t punish you for being a modern team. Terraform’s ecosystem will keep it relevant, but the direction of travel is clear: infrastructure-as-actual-code beats infrastructure-as-configuration every time.