Est.

Pulumi vs Terraform for Teams Using General-Purpose Languages

Pulumi lets teams write infrastructure in languages they already know.

· 11 min read
IaC Runtime Comparisons · October 10, 2026 · 11 min read · 2,378 words

Pulumi and Terraform both produce infrastructure as code, but the choice between them for a team already writing Python, TypeScript, or Go comes down to one question: should infrastructure live in a general-purpose language, or in a domain-specific one built just for this job? Every other difference, testing, secrets handling, hiring, abstraction, follows from that single decision. Get the authoring model right for your team, and the rest of the comparison mostly sorts itself out.

Why the authoring model matters most in this decision

Pulumi lets engineers write infrastructure in Python, TypeScript, JavaScript, Go,.NET, and Java, with YAML and HCL also supported. Terraform sticks to HCL, with Terraform JSON as a secondary format. Both tools end up declarative: you describe the desired state, and the tool figures out how to get there. The real split is in how you write that description, not in what the tool does with it once you're done.

Take a team writing TypeScript. In Pulumi, they loop over a list of environments with a standard array map, pull in an npm package to handle some shared logic, and write an if-statement that works exactly the way it does in their application code. In Terraform, the same task runs through for_each, count, and a set of built-in expression functions that don't behave like the control flow the team uses every day. Neither approach is sloppy. HCL reads cleanly in isolation, precisely because it's constrained, and that constraint is part of its appeal. But a general-purpose language composes with whatever the team already knows, and that's the fork in the road this whole comparison runs from.

How testing diverges once the authoring model is fixed

Testing is where the authoring-model choice raises the most friction in daily engineering work. With Pulumi, unit tests run in whatever framework the language already uses, Jest for TypeScript, pytest for Python, Go's built-in testing package, and resource calls get mocked out. A team that already tests application code this way picks up infrastructure testing without learning a new tool.

Terraform's path runs through terraform test, which executes.tftest.hcl or.tftest.json files against plan or apply output, with optional mock providers. For integration-level testing, most teams reach for Terratest, a third-party Go library built just for this. It works, and plenty of mature Terraform shops run on it, but it's a separate tool with its own syntax and its own learning curve, layered on top of HCL rather than growing out of a language the team already uses.

Neither path is weak. Terraform's testing story is real and well-established, especially for ops teams that have already invested in Terratest. But if a dev-heavy team is already running pytest or Jest in CI, Pulumi's approach means infrastructure tests look like the tests they already write, and they need no new mental model.

Secrets handling and state encryption for compliance-minded teams

Secrets handling follows the same pattern: a consequence of design philosophy, not a security decision made by either vendor on purpose. Pulumi encrypts values explicitly marked as secrets, both in transit and at rest in the state file, using per-stack encryption keys that plug into AWS KMS, Azure Key Vault, Google Cloud KMS, or HashiCorp Vault. Anything not explicitly marked as a secret, including values that probably should be, stays in plain text in the state file.

Terraform doesn't encrypt sensitive values in the state file by default. If a team uses HCP Terraform, it encrypts state at rest, but Vault integration comes as a separate product that needs its own setup. OpenTofu, the Linux Foundation's MPL-licensed fork of Terraform, closed part of this gap by adding native state encryption at the file level, something Terraform still leaves to the backend (S3 server-side encryption being the common example).

If a team is pursuing SOC 2 or HIPAA attestation, this difference shapes how many additional controls they need to build before an audit. Pulumi's default encryption of sensitive values and its native support for pluggable KMS providers means compliance-critical infrastructure gets encrypted without extra configuration, a posture that platforms like Porter, which operate inside customer cloud accounts and handle sensitive deployments by default, also prioritize at the infrastructure layer. Terraform's equivalent posture takes deliberate backend configuration and potentially a Vault deployment, which can add weeks to a compliance roadmap. Teams already running HCP Terraform or an existing Vault setup will feel this gap less than teams starting from scratch.

Abstraction and reuse: where general-purpose languages compound their advantage over time

The authoring-model gap widens as infrastructure grows, because it decides whether shared logic turns into a reusable library or a pile of copy-pasted modules. Pulumi lets teams write Component Resources in any supported language, and a component built in one language can be consumed from any other through Pulumi Packages. A Go team can publish an internal networking abstraction, and a Python team on the same account imports it like any other dependency.

Terraform's modularity runs through HCL modules and the public module registry, which is large, mature, and genuinely useful. The limit occurs when logic can't be expressed in HCL itself: dynamic behavior has to route through for_each, count, or external data sources, and anything beyond that can't be packaged into a module the way a function gets packaged into a library.

BMW's Software Factory offers a concrete, named example of this pattern at scale: it manages cloud resources using Python-based infrastructure code, an enterprise-scale case where language-native abstraction held up under real resource counts. That's not a claim that every team needs BMW's scale to benefit, just evidence that the pattern works when it's pushed hard.

The flexibility that makes this possible also creates a risk. Because a full programming language is available, it's possible to build infrastructure that makes dynamic database queries or calls out to third-party APIs during deployment, infrastructure that behaves differently each time it runs and is hard for anyone but the original author to debug. The fix is discipline: treat Pulumi programs the way application code gets treated, with code review, shared conventions, and the same preference for boring, predictable patterns that keeps a codebase maintainable.

The provider ecosystem gap

Terraform's provider ecosystem is its biggest advantage over Pulumi, so a team leaning toward Pulumi needs to measure that gap honestly before it commits. Terraform's public module registry is larger, and it has a longer tail of community-maintained providers that cover niche services, internal tooling integrations, and SaaS platforms most teams haven't noticed yet. If a provider exists for an unusual tool, there's a better chance it exists for Terraform first.

Pulumi's answer to this comes in two parts. Any existing Terraform provider can be adapted for use in Pulumi, and Pulumi also ships schema-generated native providers for Kubernetes, Azure Native, and AWS Cloud Control. Because these are generated directly from the underlying API schemas rather than hand-written, they pick up new upstream API features the same day those features ship.

One bridge option disappeared recently: CDK for Terraform (CDKTF), which let TypeScript teams write Terraform-style infrastructure while keeping full access to Terraform's provider coverage, was archived on December 10, 2025. That removes a middle path some teams had been using to delay the Pulumi-or-Terraform decision.

If a team works mostly against AWS, Azure, or Google Cloud, it can manage the ecosystem gap either way. For teams with heavy reliance on niche providers, or an existing library of Terraform modules built up over years, the gap is wide enough to warrant a specific audit of which providers and modules the team actually depends on before switching.

Hiring pool and team readability: the human cost of each choice

Beyond the technical tradeoffs, the authoring model shapes who can join an infrastructure team and how fast they become productive once they do. Terraform is what most DevOps engineers already know. Anyone hired out of an AWS shop or a product company in the past several years has almost certainly written HCL, which makes the Terraform hiring pool larger by a wide margin.

HCL's rigidity cuts both ways. The same constraint that limits what you can express also makes a Terraform plan easy to read cold: a junior DevOps engineer can look at a plan and understand the blast radius of a change without tracing through the program logic that produced it. Pulumi's pitch runs the opposite direction. A Python or TypeScript developer doesn't need to learn a new language to touch infrastructure, so the team's existing application engineers can already review and contribute to infrastructure code through the same pull-request process they use for everything else.

This is a real tradeoff, not a case where one side is obviously right. Terraform fits a team that hires dedicated infrastructure engineers into an established ops culture. Pulumi fits developer-heavy teams where the same engineers write application code and infrastructure code, and where introducing a separate DSL would split the team into people who can touch infrastructure and people who can't. The "magic infrastructure" risk from the abstraction section matters here too: Pulumi's flexibility makes it possible to write infrastructure code that only its original author can follow, so the readability upside depends on the team actually enforcing the same review discipline it applies to application code.

OpenTofu: Terraform's model under an OSI license

A third path exists alongside Pulumi and Terraform: OpenTofu, which keeps Terraform's HCL workflow and provider ecosystem while running under a permissively licensed, community-governed model. In August 2023, HashiCorp moved Terraform from the MPL license to the Business Source License. A coalition of users and vendors forked the last MPL-licensed release into OpenTofu, and it now lives under the Linux Foundation. In February 2025, IBM acquired HashiCorp, adding another layer of relevance for teams weighing long-term vendor exposure.

For a team running terraform apply against its own infrastructure, the license change made no operational difference. If a vendor builds products on top of Terraform, or a team has a policy preference for permissively licensed, community-governed tooling, OpenTofu is worth weighing as a real option. Its one substantive technical difference from Terraform is native state encryption at the file level, something Terraform still leaves to the backend.

OpenTofu leaves untouched whether a team should author infrastructure in HCL or in a general-purpose language; it just removes a licensing concern for teams that had already decided HCL was the right model, full stop on the authoring-model decision itself.

Fitting each tool into CI/CD pipelines and day-to-day deployment workflows

Both tools plug into standard CI/CD pipelines without much friction, but Pulumi's Automation API gives teams a capability Terraform has no equivalent for. The Automation API is a programmatic SDK for building custom CLIs, internal developer platforms, or services that spin up ephemeral environments without a human running the Pulumi CLI by hand (the CLI still has to be installed, since the Automation API drives it under the hood). So it fits teams that build self-serve infrastructure tooling or automatic preview environments for every pull request, a workflow that mirrors how teams running infrastructure-as-code inside a bring-your-own-cloud platform would expect their deployment pipelines to behave, with the pipeline logic living in the same codebase as the application itself.

Terraform's execution model runs through the local CLI or through remote runs in HCP Terraform or Terraform Enterprise. HCP Terraform exposes a REST API for triggering runs programmatically, but it doesn't offer the same in-process SDK integration that Pulumi's Automation API provides.

Both tools handle a failed deployment the same structural way: a partial update leaves the stack in an in-between state, and the next run reconciles toward the desired end state. Rolling back means reverting the program code and running it again, not triggering some built-in undo.

For teams that want cost visibility baked into CI, Infracost addresses the Terraform side of that need specifically: it estimates costs before deployment, flags cost regressions inside pull requests, and can integrate with OPA to block a PR that pushes spending past a set monthly threshold.

Compliance and audit trails: what each tool produces without extra configuration

Both tools generate infrastructure-as-code artifacts that function as audit evidence, but the compliance tooling built around each one differs in how mature and how integrated it is. Pulumi Cloud includes managed state for free, and it offers RBAC, audit logs, and policy management as paid features, all built directly into the platform instead of assembled from a separate ecosystem of third-party modules.

For regulated industries, healthcare, finance, government, the requirement that every infrastructure change is traceable and every resource meets a defined standard can be met with either tool, as long as it's configured properly. The configuration burden that fits better with the tooling a team already runs is what decides it.

Teams deploying through Porter already get SOC 2 and HIPAA compliance built into the deployment layer with a single click, which narrows where infrastructure-tooling-level compliance still matters. For those teams, the Pulumi-versus-Terraform decision matters most for the cloud resources managed outside Porter's scope, not for the application deployment layer itself, which Porter already covers.

A decision framework by team type, not by feature checklist

The right tool follows from how a team is built and how it already works, not from totaling up features on a spreadsheet. Pulumi fits a team already writing Python, TypeScript, or Go for application code, where the same engineers will author infrastructure, where unit-testable infrastructure and reusable internal component libraries carry real weight, and where a compliance path benefits from secrets encrypted by default without extra backend work.

Terraform, or OpenTofu, fits a team that's ops-first, or one hiring dedicated infrastructure engineers who already know HCL. It fits teams where plan readability for non-developers (product managers, security reviewers, junior DevOps engineers) matters, where provider coverage for a niche service is a hard requirement, or where an existing library of Terraform modules would take real effort to migrate away from.

OpenTofu is the right specific choice when the Terraform model already fits, but a BSL license or dependency on IBM's HCP Terraform is a policy concern worth avoiding. And the CDKTF escape hatch, TypeScript syntax paired with Terraform's provider coverage, closed for good on December 10, 2025. Teams that were counting on that middle path now face the same choice everyone else does: commit to the full Pulumi model, or stay on HCL.

More in IaC Runtime Comparisons