Terraform vs Pulumi: Choosing IaC for Multi-Cloud Reality

The honest tradeoffs between Terraform and Pulumi in 2026 — DSL vs general-purpose languages, state, secrets, and the team realities that decide for you.

Terraform vs Pulumi: Choosing IaC for Multi-Cloud Reality

The Terraform vs Pulumi conversation got more interesting in 2024-2025. Terraform changed its license (and OpenTofu forked it), Pulumi matured both its ESC product and its TypeScript/Python ergonomics, and the multi-cloud question stopped being theoretical for a lot of teams. We’ve shipped both on production work — Terraform for the boring multi-account AWS shape, Pulumi for projects where the IaC and the application code shared meaningful logic.

Neither is universally correct. Here’s how the decision plays out when you’re past the hello-world demo.

The thirty-second framing#

  • Terraform / OpenTofu is a DSL (HCL) with a planner that diffs your desired state against actual state, and applies the delta. Procedural language people sometimes call HCL constrained — it is, deliberately. The constraint is the point.
  • Pulumi is a library that exposes the same provider model in TypeScript, Python, Go, Java, and C#. Your infrastructure is written in a real general-purpose language, with classes, functions, loops, and tests.

The choice is essentially: do you want infrastructure code that looks like config or infrastructure code that looks like a normal program? Both have legitimate cases.

What’s actually different in 2026#

DimensionTerraform / OpenTofuPulumi
LanguageHCL (DSL)TypeScript / Python / Go / Java / .NET
State backendS3 / Terraform Cloud / OpenTofu stateS3 / Pulumi Cloud / SaaS
Plan + apply UXterraform plan → review → terraform applypulumi preview → review → pulumi up
Module systemModules (workspace-level reuse)Components (real classes, reusable like any library)
Provider ecosystemLargest in industry, every major and minor cloudWraps Terraform providers + native ones
SecretsVariables + state encryption + tools (Vault, Doppler)Pulumi ESC (built-in secrets layer)
Testingterratest (Go), policy with Sentinel / OPANative unit tests in your language of choice
Drift detectionterraform plan shows itpulumi preview shows it
Multi-cloudYes, via providersYes, via providers
Self-hosted free optionOpenTofu (Linux Foundation fork)Pulumi OSS (state in self-hosted backend)
License surfaceTerraform: BSL (since 2023); OpenTofu: MPLApache 2.0 (Pulumi OSS)

The license change in 2023 mattered. If you’re starting fresh and want a permissive license, OpenTofu and Pulumi are both clean choices; Terraform proper has more friction for some enterprise procurement processes now.

Where Terraform / OpenTofu wins#

The ecosystem. Terraform has the largest provider ecosystem in the industry. Every cloud, every major SaaS (Datadog, PagerDuty, Snowflake, GitHub, etc.), and every infrastructure component has a Terraform provider — usually first-class, often community-maintained. Pulumi covers all the same ground but typically by wrapping Terraform providers.

HCL’s deliberate constraints. HCL is bad at things you shouldn’t be doing in infrastructure code anyway — complex business logic, dynamic resource creation based on runtime data, clever metaprogramming. The constraints force teams to keep infrastructure code declarative and reviewable. For a 50-person platform team, this is a feature.

Hiring and onboarding. A new engineer joining your team is more likely to know Terraform than Pulumi. The body of public tutorials, blog posts, and Stack Overflow answers is much larger.

Module reuse across orgs. The Terraform Registry has thousands of vetted modules for common patterns (VPC, EKS, RDS). Plug in inputs, get back vetted outputs. Pulumi has components but the public library is much smaller.

Where Pulumi wins#

Real language for real logic. When your infrastructure setup involves logic that’s actually complicated — a multi-region rollout where each region has a different feature flag, a Kafka cluster with topic configurations defined in a JSON file that’s the source of truth, an EKS setup with per-namespace permission patterns — Pulumi lets you write that logic in the language you already know. Terraform forces you into HCL contortions (for_each over complex maps, dynamic blocks, templatefile) that are harder to read than the Python equivalent.

Testability. You can unit test Pulumi infrastructure code. Mock providers, assert on resource configurations, run it in CI. Terraform testing exists (terratest runs real infrastructure for assertions) but it’s slower and a different mental model. For platform teams shipping reusable components, native unit tests matter.

Code sharing with the app. If your application code and infrastructure code are both TypeScript (or both Python), Pulumi lets you share types, validation, and helper code between them. The Topic definition that the application reads can be the same object the infrastructure code creates.

Pulumi ESC for secrets and config. Pulumi’s ESC (Environments, Secrets, Configurations) product is a strong secrets and configuration layer that integrates with most secret backends. Terraform punts secrets to a separate tool (Vault, Doppler, etc.) which works but is one more system.

Drift detection ergonomics. Both detect drift. Pulumi’s output is generally easier to read for non-trivial state.

The cases where the choice is obvious#

Pick Terraform / OpenTofu if:

  • Your team is operations-heavy and doesn’t have strong language affinity (mixed Python / Go / TS / Ruby backgrounds).
  • You’re consuming a lot of community modules for standard patterns.
  • Your infrastructure is mostly “the standard shape” — VPCs, EKS, RDS, IAM — with little custom logic.
  • You’re integrating with tools that have first-class Terraform support (Datadog, Snowflake, Auth0) and the workflows are well-established.
  • Your platform team prefers config files over code on principle (real and valid preference).

Pick Pulumi if:

  • Your team is application-engineering-led (TypeScript or Python natives).
  • Your infrastructure has non-trivial logic — multi-region, multi-tenant, dynamic resource shapes driven by data.
  • You want unit tests and the rest of the modern software engineering toolchain on your infrastructure code.
  • You’re shipping internal platform components that other teams consume — Pulumi components feel more like libraries than Terraform modules.
  • You care about Apache 2.0 licensing specifically.

OpenTofu in 2026#

OpenTofu (the Linux Foundation fork of Terraform) is now a credible, production-grade replacement for Terraform with a small but growing list of unique features (state encryption, provider iteration, others). For new projects where you’re choosing between Terraform and OpenTofu, we’d default to OpenTofu unless you have a specific Terraform Cloud or HashiCorp commercial dependency.

The compatibility is high. Most existing Terraform configurations work on OpenTofu unchanged. The risk of being on OpenTofu and needing to switch back is low.

What we deploy by default#

For a typical greenfield cloud platform build (the kind we do for hospitals, banks, and logistics), our default is:

  1. OpenTofu for the cloud platform layer (VPC, EKS / GKE, IAM, RDS, S3 buckets, base policies).
  2. Helm + Argo CD for Kubernetes workloads on top.
  3. Vault for secrets where the cloud’s native KMS isn’t enough.
  4. GitHub Actions as the CI runner for tofu plan / tofu apply.

We use Pulumi for projects where we hit one of these triggers:

  • Multi-region deployments with non-trivial per-region differences.
  • A platform team building reusable infrastructure components for application teams to consume.
  • Applications where the application and infrastructure code share meaningful types or logic.
  • Customers who already use Pulumi internally.

We don’t usually run a mixed Terraform-and-Pulumi shop unless we inherited one. Pick one for the cloud platform layer and stick with it.

Patterns that matter more than the choice#

A few things matter more than Terraform vs Pulumi for whether your IaC works in production.

Remote state with locking. Whichever tool you pick, state lives in S3 / GCS / Azure Blob with explicit locking (DynamoDB / Pulumi Cloud / etc.). State files on someone’s laptop is how production gets accidentally destroyed.

Plan-then-apply, always, on a PR. Run plan (or preview) in CI on every PR, with the output as a comment. Humans review the plan before merge. The applied delta in production should match what was reviewed.

One state file per blast-radius boundary. Don’t put production and staging in the same state file. Don’t put prod-us-east-1 and prod-eu-west-1 in the same state file unless you really need to. Smaller blast radii recover faster from incidents.

Module / component versioning. Pin module versions. Bump deliberately. “Latest” in your IaC is how a Tuesday-morning surprise becomes a Tuesday-morning incident.

Drift detection as a scheduled job. Run plan / preview on a schedule (daily, hourly for prod) and alert on unexpected drift. Drift means someone changed something via the console, and that’s worth knowing.

These apply equally to either tool. If you have them, the choice between Terraform and Pulumi is mostly stylistic. If you don’t, no tool will save you.

The meta-point#

The IaC tool is one decision out of many in a cloud platform build, and not the most important one. The shape of your network, the IAM model, the secrets architecture, the CI/CD topology — these decide whether your platform is operable. The IaC tool is how you express those decisions.

Pick the tool that fits your team’s language affinity and the complexity of your logic. Run plan-then-apply on every PR. Don’t share state across blast radii. The rest is details.


The IaC tool matters less than the platform decisions it expresses. If you’re standing up a new cloud platform and want a second pair of eyes on the topology, our DevOps and cloud infrastructure team has shipped both Terraform and Pulumi in production. Tell us about the shape.