Skip to content

IaC

Domain summary

Infrastructure as Code tools that declare cloud, SaaS and on-premises resources, compute a plan against recorded state, and apply it through provider plugins. The domain covers Terraform 1.16.4 (BSL 1.1, HashiCorp, an IBM company), its open-source fork OpenTofu 1.12.6 (MPL-2.0, Linux Foundation, CNCF Sandbox), and Pulumi 3.264.0 (Apache-2.0 engine, general-purpose languages plus YAML and HCL). All three can use the same Terraform-protocol providers. They differ in license and governance, in how state is protected, and in the language you write.

← Knowledge Base

Topics

Topic What it is Current version (checked 2026-09-25) License
OpenTofu Open-source fork of Terraform 1.5.x under the Linux Foundation (CNCF Sandbox since 2025-04-23). Same HCL, state and providers, plus client-side state and plan encryption, early variable evaluation, provider for_each and OCI distribution 1.12.6 (2026-08-19); 1.13 in RC MPL-2.0
Pulumi IaC in TypeScript/JavaScript, Python, Go, .NET, Java, YAML or HCL on an open-source engine; commercial Pulumi Cloud adds state, ESC secrets, Deployments, Neo AI agent and IDP 3.264.0 (2026-09-23), roughly weekly releases Apache-2.0 (CLI, engine, SDKs); Pulumi Cloud proprietary
Terraform HashiCorp's declarative HCL tool with the largest provider and module ecosystem; HCP Terraform and Terraform Enterprise add remote runs, policy, Stacks and HYOK 1.16.4 (2026-09-23); 1.17 in beta BSL 1.1 since 1.6 (licensor IBM); 1.5.7 was the last MPL-2.0 release

How the Domain Fits Together

The map shows the shared provider protocol at the centre: OpenTofu forked from Terraform 1.5.x, Pulumi can run any Terraform/OpenTofu provider and even .tf files, and each tool has its own managed platform and state options.

flowchart LR
    TF["Terraform 1.16<br/>(BSL 1.1)"] -->|"forked at 1.5.x"| OT["OpenTofu 1.12<br/>(MPL-2.0)"]
    TF -->|"tfplugin5/6 gRPC"| PROV["Terraform-protocol providers<br/>(aws, azurerm, google, kubernetes)"]
    OT -->|"tfplugin5/6 gRPC"| PROV
    PU["Pulumi 3.264<br/>(Apache-2.0)"] -->|"bridged packages +<br/>Any Terraform Provider"| PROV
    PU -.->|"Pulumi HCL runs .tf files"| TF
    TF --> HCP["HCP Terraform / TFE<br/>(Stacks, Sentinel/OPA, HYOK)"]
    OT --> TACOS["Third-party TACOS<br/>(Spacelift, env0, Scalr, Harness)"]
    OT --> ENC["Client-side state and<br/>plan encryption"]
    PU --> PC["Pulumi Cloud<br/>(ESC, Neo, Deployments, IDP)"]
    PROV --> CLOUD["Cloud and SaaS APIs"]

Comparisons

Comparison Scope
IaC Comparison: Terraform vs OpenTofu vs Pulumi License and governance, languages, providers, state backends, locking and encryption, testing, policy, managed platforms, migration paths, and a decision flowchart

All comparison notes are listed in the comparisons index.

When to Use Which

These rules match the decision flowchart in the IaC comparison.

Need Reach for
Real programming languages, unit tests, Automation API, self-service platforms Pulumi
HCL with an OSI open-source license and neutral foundation governance OpenTofu
Client-side encryption of state and plan files regardless of backend OpenTofu
HCP Terraform features (Stacks, Sentinel, HYOK, no-code modules) or IBM/HashiCorp support Terraform
Existing Terraform 1.5.x or earlier and a license concern OpenTofu (drop-in migration)
Existing Terraform 1.6+ configurations Stay on Terraform, or review Terraform-only features before moving to OpenTofu
HCL authoring but Pulumi Cloud services (ESC, Neo, Deployments) Pulumi with Pulumi HCL (runtime: hcl)

Landscape

The main tension is between a declarative DSL (HCL in Terraform and OpenTofu) and general-purpose languages (Pulumi). HCL keeps plans reviewable by people with little programming background. General-purpose languages add loops, types, abstractions and unit tests, at the cost of a steeper abstraction curve. The line is blurring: Terraform keeps adding language features (dynamic module sources in 1.15, import inside modules in 1.16), and Pulumi now runs HCL directly.

HashiCorp relicensed Terraform from MPL 2.0 to BSL 1.1 with version 1.6 (2023). The community forked 1.5.x as OpenTofu under the Linux Foundation, and OpenTofu joined the CNCF Sandbox on 2025-04-23. IBM completed its acquisition of HashiCorp on 2025-02-27 and is now the licensor named in Terraform's license. CDKTF, HashiCorp's general-purpose-language layer, was archived on 2025-12-10, which leaves Pulumi as the main general-purpose-language option among these tools.

The provider ecosystem is the strongest moat, but it is shared: Terraform, OpenTofu and Pulumi can all run the same Terraform-protocol provider binaries. The Terraform Registry lists thousands of providers: the registry home page showed 7,335 providers and 24,598 modules in a search-engine snapshot seen 2026-09-27. OpenTofu runs its own registry at registry.opentofu.org and adds OCI distribution since 1.10.

Layered IaC

A common platform pattern is layered IaC: infrastructure teams keep low-level Terraform or OpenTofu modules, and platform teams expose them through higher-level APIs such as Pulumi components, the Pulumi Automation API, or Crossplane compositions. Developers get a self-service interface without writing provider-level code.

Single-cloud tools (AWS CDK, Azure Bicep, Google Cloud Infrastructure Manager) integrate more tightly with one provider but give up multi-cloud reach. Google's older Cloud Deployment Manager reached end of support on 2026-03-31, with Infrastructure Manager as the suggested replacement. The runner layer (often called TACOS: Atlantis, Spacelift, env0, Scalr, Harness, HCP Terraform) provides plan/apply automation, policy, drift checks and state hosting.

Key Concepts

State Management

IaC tools keep a state file that maps declared resources to real objects, which enables diff-based plans. Terraform and OpenTofu store state as JSON in a backend (local, S3, GCS, AzureRM, PostgreSQL and others, or HCP Terraform). Pulumi keeps per-stack state in Pulumi Cloud or a DIY backend (S3 and S3-compatible, Azure Blob, GCS, PostgreSQL, local file).

  • Locking: prevents concurrent writes. On S3, Terraform (GA in 1.11) and OpenTofu (1.10+) support a native lock file with use_lockfile = true; Terraform deprecated the DynamoDB locking arguments. Other backends use blob leases, lock objects or PostgreSQL advisory locks. Pulumi Cloud locks service-side, and DIY backends use lock files.
  • Encryption: OpenTofu encrypts state and plan files client-side since 1.7 (aes_gcm with keys from pbkdf2, aws_kms, gcp_kms, openbao, azure_vault or the experimental external provider). Terraform relies on backend encryption at rest; HCP Terraform adds Hold Your Own Key (HYOK, GA 2025-09). Pulumi encrypts each secret value in state with the stack's secrets provider (Pulumi Cloud, passphrase, AWS KMS, Azure Key Vault, Google Cloud KMS or Vault Transit), including on DIY backends.
  • Keeping secrets out of state: ephemeral values and write-only attributes (Terraform 1.10/1.11, OpenTofu 1.11) never persist sensitive values.
  • Splitting: smaller states reduce blast radius and plan time.
  • Import: import blocks (Terraform 1.5+, OpenTofu from its first release 1.6, with for_each since 1.7) and pulumi import bring existing resources under management. Terraform 1.14 added terraform query to discover resources to import.

Plan/Apply Workflow

plan computes the diff between desired and recorded state without changing anything; apply executes it. Pulumi's equivalents are pulumi preview and pulumi up. Policy-as-code gates can reject a plan before any change:

  • Sentinel and OPA: policy sets on HCP Terraform and Terraform Enterprise. Terraform Policy (-policies) brings evaluation to the CLI and is GA in the 1.17 line, currently in beta.
  • OPA/Rego with Conftest: evaluates plan JSON from Terraform or OpenTofu in any CI system.
  • Pulumi policy packs (formerly branded CrossGuard): policies written in general-purpose languages, enforced across the organization through Pulumi Cloud.

Drift Detection

Drift happens when live infrastructure changes outside IaC (console edits, other automation). Terraform and OpenTofu detect it during plan by refreshing state against provider APIs, and Pulumi with pulumi refresh or preview. None of the CLIs poll on their own, so continuous detection needs scheduled plans in CI or a managed platform (for example Pulumi Cloud drift detection on the Pro edition and above). Crossplane takes a different approach: Kubernetes controllers continuously reconcile managed resources against their spec.

Providers and Modules

Provider model

Providers are plugins that translate resource definitions into cloud API calls over gRPC (plugin protocol 5/6). The same provider binaries serve Terraform and OpenTofu, and Pulumi runs them through bridged packages or pulumi package add terraform-provider. Lock files (.terraform.lock.hcl) pin provider versions and checksums for reproducible runs.

Reusable modules come from the Terraform Registry, the OpenTofu Registry (and OCI registries since OpenTofu 1.10), private registries, or Git. Pulumi components are shipped through language package managers (npm, PyPI, NuGet, Maven, Go modules) and Pulumi's private registry, which adds type checking and richer dependency resolution.

Sources

Open Questions

  • As Terraform (Stacks, actions, list resources, dynamic module sources) and OpenTofu (state encryption, provider for_each, OCI distribution, Symbol Libraries) keep diverging, will providers and modules stay portable between them?
  • With Pulumi running HCL and Terraform adding more programming constructs, does the DSL-versus-general-purpose-language choice still decide tool selection, or do platform services (HCP Terraform, Pulumi Cloud, TACOS) decide it instead?
  • What is the best practice for "state as a liability" at scale (hundreds of states) now that ephemeral values, write-only attributes, OpenTofu encryption and HYOK each cover part of the problem?