Terraform, OpenTofu and Pulumi: Why I Still Run Terraform in 2026

Infrastructure as Code stopped being a single-answer question a couple of years ago. Terraform went BSL in August 2023, OpenTofu forked under MPL, Pulumi kept arguing that infrastructure should be real code in real languages, and IBM closed the $6.4B HashiCorp acquisition in February 2025. Three legitimate tools, three different bets on who owns the abstraction.

I still run Terraform. For everything.

This post is the honest version of why. I’ve read the OpenTofu release notes, watched Pulumi talks, played with both on weekend projects, and read more migration write-ups than I can remember. I have never put OpenTofu or Pulumi in front of production traffic. Most of what follows about those two is research, not muscle memory — and I’ll flag that as I go.

Terraform: what I actually run

Terraform 1.14 went stable in March 2026 (1.14.8 is the current patch), and 1.15 is in release candidates with Windows ARM64 support. Under IBM, HashiCorp has settled Terraform Enterprise on a roughly quarterly cadence, and the open CLI follows the same drumbeat.

My stack hasn’t changed shape in years:

  • Terraform CLI for plan / apply.
  • S3 + DynamoDB for state and locking, one bucket per environment.
  • GitHub Actions for PR-based plan and apply — no HCP, no Atlantis.
  • A pile of modules I’ve written or forked, pinned by tag.
  • tflint and tfsec in CI, plus terraform validate as a smoke test.

It is profoundly boring. That’s the point. When something breaks at 2 a.m., the answer is already on Stack Overflow because someone hit it in 2019. When a junior on the team needs to ship a change, the mental model fits in their head before the second coffee. When a new cloud service launches, the provider ships within weeks.

What I like about Terraform in 2026:

  • Ecosystem gravity. Every cloud, every SaaS, every internal platform team ships a Terraform provider before anything else. AWS, Azure, GCP, Kubernetes, Datadog, GitHub, Cloudflare — the providers are first-class. The long tail of niche providers is even longer.
  • Twelve years of answers. Stack Overflow, blog posts, books, conference talks, hallway conversations. The collective debugging history is enormous and that matters more than people admit.
  • Stable enough to forget about. Backwards compatibility has been good. I have repos that haven’t needed a tooling change in two years.
  • State backends that survived production. S3 + DynamoDB has been punished and it keeps working. I trust it the way I trust ext4.

What I don’t love:

  • BSL since August 2023. Terraform moved from MPL 2.0 to the Business Source License 1.1. The licence forbids running a competing managed service. For me, building infrastructure for customers, this changes nothing — I’m a user, not a competitor. Legal hasn’t blinked. But I understand teams whose legal has blinked.

  • HCP free tier is ending. HashiCorp announced in December 2025 that the legacy free plan reaches end-of-life on March 31, 2026. Existing organisations migrate to an “enhanced free” tier (up to 500 managed resources, unlimited users, one concurrent run). Paid tiers are:

    • Essentials: $0.10 / resource / month
    • Standard: $0.47 / resource / month
    • Premium: $0.99 / resource / month

    At Premium pricing, a 5,000-resource stack costs $59,400/year for the workflow tool. I don’t run HCP anyway, so this doesn’t touch me — but it’s the reason a lot of teams are finally evaluating the alternatives this year.

  • No native state encryption. State is plaintext-at-rest unless your backend (S3 SSE, GCS CMEK) does it for you. I let S3 + KMS handle it. That’s been good enough for every auditor I’ve worked with, but I won’t pretend it’s the same as client-side AES-GCM.

That’s it. The reasons I’m still on Terraform are not exciting. There is no compliance mandate forcing me off BSL. There is no performance ceiling I’ve hit. There is no feature I desperately want that OpenTofu or Pulumi has and Terraform doesn’t. Inertia plus the ecosystem keeps winning.

OpenTofu: what I’ve read, not what I’ve shipped

Honest disclaimer: I have not run OpenTofu in production. Everything below comes from the release notes, the public roadmap, talks from the steering committee, and a couple of small spike branches on my laptop.

OpenTofu was born from the BSL switch in late 2023 and is now a Linux Foundation project with a steering committee drawn from across the ecosystem. The current series is 1.11, with 1.12 in development. Boeing, Capital One, and AMD are public production users; community surveys put adoption around 12% of practitioners in early 2026, with another 27% evaluating.

What looks genuinely good on paper:

  • Drop-in binary replacement. Same HCL, same providers, same state file format. tofu init && tofu plan on an existing Terraform codebase is reported to work the vast majority of the time. The CLI even reads .terraformrc and TF_* environment variables.
  • Native client-side state encryption. Since 1.7, OpenTofu can encrypt state and plan files at rest using AES-GCM, with multiple key providers: PBKDF2 (passphrase), AWS KMS, GCP KMS, and HashiCorp Vault. This is the single feature most write-ups quote when justifying a switch.
  • Ephemeral resources and write-only attributes (1.11). Secrets that exist in memory during a run but are never written to state. Useful for credentials, short-lived tokens, dynamic database passwords.
  • Permissive licence stays permissive. MPL 2.0, governed by a foundation, with a public roadmap. No acquisition scenario flips this.
  • Provider compatibility. The OpenTofu registry mirrors the Terraform registry. As of 1.12, the registry serves official checksums in all required formats.

Where it would cost me something to adopt:

  • No first-party Terraform Cloud equivalent. The OpenTofu project does not run a hosted workflow product. You bring your own: Spacelift, env0, Scalr, Atlantis, or roll something in CI. Since I already run on GitHub Actions, this is a non-issue for me — but it’s a real evaluation item for teams that bought into HCP.
  • No built-in policy framework. No native Sentinel. You can use OPA via integrations, or whatever your workflow product ships.
  • Ecosystem still follows Terraform’s pace. Provider authors usually publish to both registries, but Terraform-first is still the norm. A handful of niche providers lag by a release or two.
  • Smaller community. Growing fast, but the answer to a weird error is still more likely to be a Terraform answer than an OpenTofu-specific one.

So why haven’t I switched? Three reasons:

  1. No compliance mandate. Nobody on my side is asking for client-side state encryption at the Terraform layer. S3 SSE-KMS has cleared every audit I’ve been through.
  2. No licence pressure. I’m not a managed-service competitor. BSL is fine for my use case.
  3. Migration cost isn’t zero, even when it’s “trivial” on paper. Across half a dozen repos, with CI pipelines, internal modules, pinned provider versions, and people who would need to re-learn a binary name, “drop-in” still costs me a week I don’t have for a benefit I can’t quantify.

If any of those three flipped — a new auditor, a new legal posture, a real feature I needed — OpenTofu is the first place I’d look. I keep an eye on the release notes for exactly that reason.

Pulumi: a different bet, also not mine

Same disclaimer: I have not run Pulumi in production. I’ve worked through tutorials, read the docs, and shipped one toy stack on a side project. Most of what follows is research and second-hand reports.

Pulumi takes a different bet entirely: infrastructure is code, so use real code. You write TypeScript, Python, Go, C#, Java, or YAML, the SDK builds a resource graph, and the Pulumi engine diffs that graph against state and applies it. The provider layer is largely the same Terraform providers, wrapped.

What’s genuinely interesting:

  • Component resources. A Service class that encapsulates a Deployment, Service, Ingress, ServiceMonitor, and HPA is just a class. You publish it as a package on your internal registry. Application teams import it and pass parameters. This is the “golden path” abstraction people talk about when they talk about Pulumi, and on paper it’s cleaner than Terraform modules.
  • Pulumi ESC. Environments, Secrets, and Configuration — a hosted secrets/config layer that integrates with cloud KMS, Vault, and OIDC. It works outside Pulumi (CLI, SDKs, OIDC providers), so the same secret tree feeds Kubernetes, CI, and shell sessions. Priced per secret-hour (~$0.50/secret/mo on Team, $0.75 on Enterprise).
  • CrossGuard policy in any language. OPA via Rego, or policy-as-code in TypeScript / Python. Unit-testable.
  • Real testing. Mock providers, snapshot tests, full integration tests in your language’s standard test framework (pytest, go test, jest).
  • Self-hosted state. Pulumi state can sit in S3, GCS, Azure Blob, or local disk.

Where the bet starts to cost:

  • The abstraction is the hard part, not the language. Every write-up I’ve read says the same thing: teams new to Pulumi often write Pulumi as if it were Terraform with if statements, and the result is worse than either. Learning when to write a Component, a function, or a Stack takes real projects.
  • Provider coverage in the long tail. First-party providers for the big clouds and Kubernetes are excellent. Obscure SaaS providers sometimes lag.
  • DIY state management. You pick your backend, your backup strategy, your conventions.
  • Performance on large stacks. Reports of Pulumi planning large stacks noticeably slower than Terraform on the same provider set. For 50-resource stacks you’ll never notice; for 5,000-resource stacks people say you feel it. I have not benchmarked this myself.

The honest reason I haven’t moved to Pulumi: it solves a problem I don’t have. My HCL isn’t suffering. My modules aren’t reaching the expressiveness ceiling. I don’t have application teams clamouring for a paved road in Python. If I were starting a platform team from scratch, in a Python or Go shop, with the explicit goal of shipping internal components as packages, Pulumi would be on the shortlist — exactly the scenario its design optimises for.

A bucket, three ways

Just to put the syntactic difference on the page. Terraform / OpenTofu (HCL):

resource "aws_s3_bucket" "data" {
  bucket = "falcao-prod-data"
  tags   = { Env = "prod", Owner = "platform" }
}

resource "aws_s3_bucket_versioning" "data" {
  bucket = aws_s3_bucket.data.id
  versioning_configuration { status = "Enabled" }
}

resource "aws_s3_bucket_server_side_encryption_configuration" "data" {
  bucket = aws_s3_bucket.data.id
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

Pulumi (Python):

import pulumi_aws as aws

bucket = aws.s3.BucketV2("data",
    bucket="falcao-prod-data",
    tags={"Env": "prod", "Owner": "platform"})

aws.s3.BucketVersioningV2("data-versioning",
    bucket=bucket.id,
    versioning_configuration={"status": "Enabled"})

aws.s3.BucketServerSideEncryptionConfigurationV2("data-sse",
    bucket=bucket.id,
    rules=[{"apply_server_side_encryption_by_default":
            {"sse_algorithm": "AES256"}}])

Roughly the same line count for the same resource. The argument for Pulumi isn’t “fewer lines” — it’s “what happens when you need a loop, a conditional, a shared helper, or a class”. HCL has for_each, dynamic blocks, and locals; for what I do, those have been enough.

State, locking, drift

Terraform 1.14OpenTofu 1.11Pulumi
Default backendLocal / S3 / HCPLocal / S3Pulumi Cloud / S3 / GCS / Azure
Client-side encryptionNoYes (AES-GCM, PBKDF2/KMS/Vault)Yes (per-stack passphrase or KMS)
LockingBackend-native (DynamoDB, etc.)Backend-nativeBackend-native
Drift detectionterraform plantofu planpulumi refresh + pulumi preview
State formatJSON, versionedJSON, versioned (compatible)JSON, checkpointed
Import existing resourcesterraform import + import blockstofu import + import blockspulumi import (codegen)

The notable line is client-side encryption. If your auditor wants state encrypted with a key you control, OpenTofu and Pulumi answer it natively; Terraform answers it via the backend.

When the answer would actually change

Five scenarios where I would seriously consider moving — none of which describe my current work:

  1. A new auditor decides backend-level encryption isn’t enough. That’s the OpenTofu case. Drop-in, MPL, foundation-governed.
  2. Legal flips on BSL. Also OpenTofu. Same migration story.
  3. I’m building a platform team in a Python shop and the entire point is publishing reusable components to app teams. That’s Pulumi with component resources.
  4. A team I join is already on one of the alternatives. Then I meet them where they are. There is no world where I rip out a working OpenTofu or Pulumi stack to bring it back to Terraform.
  5. HashiCorp does something genuinely user-hostile. Hasn’t happened yet. BSL was a corporate-licence move, not a user-hostile one. The HCP pricing change is annoying but it doesn’t touch people who never used HCP.

Until one of those flips, I’m staying. The cost of a migration — training, CI changes, provider quirks, the inevitable two-week tail of “why does plan output look slightly different now” — has to be paid by some benefit, and right now there isn’t one for me.

Closing

The IaC question used to be a tool question. In 2026 it’s an abstraction-ownership question:

  • If you want the community to own the abstraction, Terraform is the obvious pick.
  • If you want the foundation to own the abstraction, OpenTofu.
  • If you want to own the abstraction itself, Pulumi.

All three engines will create the same VPC, the same cluster, the same database. What differs is who owns the building blocks above them.

For me, in 2026, that owner is still the Terraform ecosystem. Not because the others are worse — they’re not. Because nothing about my work has made the migration worth its cost. That’s a much more boring answer than “Tool X is the best”, and it’s the honest one.

If you’re using OpenTofu or Pulumi in production, I’d love to hear which constraint actually pushed you off Terraform. That’s the information I’m missing, and the one that would change my mind first.