Skip to main content
Pulumi logo Pulumi logo
  1. Docs
  2. Infrastructure as Code
  3. Comparisons
  4. OpenTofu

Pulumi vs. OpenTofu

    Pulumi and OpenTofu are both declarative infrastructure as code tools that provision resources across clouds and SaaS platforms. Pulumi lets you define infrastructure in general-purpose languages (Python, TypeScript, JavaScript, Go, .NET, and Java), as well as YAML and HCL itself; OpenTofu is a Linux Foundation fork of Terraform that uses the HashiCorp Configuration Language (HCL).

    The two are unusually interoperable. Pulumi HCL runs valid OpenTofu configurations, with a short list of documented exceptions, and resolves providers against the OpenTofu registry by default. Pulumi Cloud can operate as a managed OpenTofu backend and remote runner for the tofu CLI. Pulumi programs can execute your existing OpenTofu modules. Adopting Pulumi does not require leaving HCL, your modules, or the OpenTofu ecosystem behind.

    This page covers what each tool is, a feature-by-feature comparison, the most important differences in detail, and the available paths for adopting Pulumi alongside or instead of OpenTofu.

    What is Pulumi?

    Pulumi is an infrastructure as code platform for provisioning and managing resources across any cloud or SaaS platform. Pulumi programs are written in general-purpose programming languages — Python, TypeScript, JavaScript, Go, .NET, and Java — as well as YAML and HCL. The Pulumi Registry covers all major clouds, including first-party native providers that are generated from upstream API schemas for same-day coverage of new platform features. The Pulumi CLI and SDKs are open source under the Apache 2.0 license. Pulumi Cloud is the commercial product that adds managed state, secrets, RBAC, audit logs, policy management, and other features for running Pulumi at organizational scale.

    For users coming from OpenTofu, Pulumi can also consume the existing OpenTofu ecosystem directly: the Any Terraform Provider feature generates a typed Pulumi SDK from any provider in the OpenTofu or Terraform registry, and Pulumi can execute existing OpenTofu modules as components inside a Pulumi program.

    Pulumi also runs HCL itself. Pulumi HCL is a first-class Pulumi language: set runtime: hcl in Pulumi.yaml, keep your .tf files, and providers resolve against the OpenTofu registry and are bridged automatically, exactly as they are in OpenTofu. The syntax is the same, apart from a short list of documented exceptions.

    What is OpenTofu?

    OpenTofu is an open-source, declarative infrastructure as code tool forked from Terraform 1.6 and governed by the Linux Foundation. OpenTofu uses the Mozilla Public License 2.0 and the HashiCorp Configuration Language (HCL), the same DSL as Terraform. OpenTofu supports the same provider ecosystem as Terraform — the OpenTofu Registry indexes the same providers as the Terraform Registry, along with additional community providers. OpenTofu itself has no commercial tier; managed-state and collaboration features come from third-party services such as Spacelift, env0, and Scalr.

    Detailed comparison

    FeaturePulumiOpenTofu
    Language supportPython, TypeScript, JavaScript, Go, .NET, and Java — general-purpose languages with familiar syntax for loops, conditionals, and abstractions — plus YAML and HCL, which runs valid OpenTofu configurations with a short list of documented exceptions and resolves providers against the OpenTofu registry by defaultHashiCorp Configuration Language (HCL) — a declarative DSL with a fixed set of functions and meta-arguments
    Cloud and service supportPulumi Registry of packages, including bridged, native, parameterized, and dynamic providers; first-party native providers for Kubernetes and Azure Native generated from upstream API schemas; any OpenTofu or Terraform provider can be generated into a Pulumi SDK with pulumi package add terraform-provider <name>Providers from the OpenTofu Registry or the Terraform Registry; community and custom providers are installed and pinned through the required_providers block
    Transpiled to another format?No — programs run directly in their host languageNo — HCL is interpreted by the OpenTofu CLI
    State managementManaged by Pulumi Cloud by default; self-managed backends include Amazon S3, Azure Blob Storage, Google Cloud Storage, local files, and others; Pulumi Cloud can also operate as an OpenTofu backendSelf-managed by default (local file); remote backends include S3, GCS, Azure Blob, HTTP, and others; managed offerings available from Pulumi Cloud and third parties (Spacelift, env0, Scalr)
    Secrets managementEncrypted in transit and at rest in the state file by default, with per-stack encryption keys; pluggable KMS providers (AWS KMS, Azure Key Vault, Google Cloud KMS, HashiCorp Vault)State and plan encryption (added in OpenTofu 1.7) with pluggable key providers; individual variable values are not encrypted as a first-class primitive
    Execution modelLocal CLI, programmatic via Automation API, or remote runs in Pulumi DeploymentsLocal CLI; remote execution requires a runner — Pulumi Cloud runs tofu plans and applies when it backs your state, or use a third-party service
    Rollback on failed operationFailed updates leave the stack in a partially-updated state; subsequent pulumi up runs reconcile toward the desired state, and you can roll forward by reverting program codeNo automatic rollback; failed tofu apply runs leave resources in their last reported state and require a follow-up apply to reconcile
    Programmatic API for tools and platformsAutomation API — a programmatic SDK for building custom CLIs, internal developer platforms, and services that drive up, preview, and destroy without shelling out to the Pulumi CLINo embeddable SDK; orchestration goes through tofu CLI invocations
    Modularity and reuseComponent Resources authored in any supported language; Pulumi Packages let a component written in one language be consumed from any Pulumi language; language-native package managers (npm, PyPI, NuGet, Maven, Go modules); and the Pulumi Registry for publicly available packagesModules referenced from local paths, Git, or registries; Pulumi can also consume OpenTofu modules directly and host them in Pulumi Cloud’s registry, where tofu init can still resolve them
    Import existing resourcespulumi import and the import resource option, both of which generate code in your languagetofu import and the import block; HCL for the imported resource must be authored by hand
    Policy as codePulumi Policies — open source, with rules written in Python, TypeScript, or Open Policy Agent Rego; Pulumi Cloud commercial plans add centralized policy management plus Pulumi-maintained policy packs for compliance frameworks like CIS, HITRUST, NIST, and PCI DSSNo built-in policy-as-code; external tools such as Open Policy Agent or Checkov can evaluate plan output
    Open sourceYes — Apache License 2.0Yes — Mozilla Public License 2.0
    Commercial optionPulumi CloudNone from the OpenTofu project itself; commercial managed-state and collaboration tooling comes from Pulumi Cloud or third parties (Spacelift, env0, Scalr)

    Key differences

    Language support and the authoring experience

    OpenTofu configurations are written in HCL, a declarative DSL with a fixed set of built-in functions and meta-arguments (for_each, count, dynamic) for shaping resources. HCL is declarative and configuration-focused. General-purpose languages offer a different model, with classes, richer runtime logic, package management, IDE features (autocomplete, type checking, refactoring, go-to-definition), and the testing frameworks that already exist in those ecosystems, so Pulumi lets you choose the approach that fits the project. Pulumi supports HCL natively as well, alongside YAML for users who prefer a markup format.

    Pulumi does not require you to give up HCL to get any of this. Pulumi HCL is a first-class language that runs the HCL you already write, with a short list of documented exceptions, down to resolving unqualified provider sources against the OpenTofu registry. The practical difference is that on Pulumi the language is a per-project decision you can revisit — an HCL project and a Go project share the same components, modules, state model, and policies — whereas on OpenTofu, HCL is the only option.

    Cloud and service coverage

    OpenTofu and Pulumi target broadly the same set of clouds and SaaS platforms, but reach them through different mechanisms. OpenTofu uses providers from the OpenTofu Registry (and, where compatible, the Terraform Registry), installed and pinned through the required_providers block. Pulumi pulls from the Pulumi Registry, which includes bridged, native, parameterized, and dynamic providers. Pulumi also maintains native providers for Kubernetes and Azure Native, generated directly from each platform’s API schema for same-day coverage of new resources.

    When a provider is not packaged in the Pulumi Registry, the Any Terraform Provider feature generates a typed Pulumi SDK from any provider in the OpenTofu or Terraform registry by running pulumi package add terraform-provider <name>. The result is a strongly typed local SDK usable from any Pulumi language — so an OpenTofu user’s existing third-party providers are first-class citizens in Pulumi without writing or maintaining a separate bridge.

    Execution and rollbacks

    OpenTofu runs locally through the tofu CLI; remote execution requires a runner. That runner can be Pulumi Cloud: when it holds your OpenTofu state, stacks created through the CLI run plans and applies on Pulumi Cloud by default, with VCS-triggered applies pausing for manual approval, so you get managed remote runs without adopting a third-party service (Spacelift, env0, Scalr) or building a custom CI pipeline. Pulumi itself runs through the local CLI, programmatically through the Automation API, or remotely through Pulumi Deployments. Neither tool performs automatic rollback on a failed apply/up: both leave the stack in a partially updated state and reconcile on the next run. The difference is in surface area — Pulumi offers an embeddable SDK and a first-party managed runner; OpenTofu relies on the CLI and external automation.

    Secrets handling

    Pulumi treats secrets as a first-class primitive. Values marked as secrets are encrypted in transit and at rest in the state file, anything derived from a secret is also encrypted, and each stack has its own encryption key. The default encryption provider can be replaced with AWS KMS, Azure Key Vault, Google Cloud KMS, or HashiCorp Vault. OpenTofu added state and plan encryption in version 1.7, which encrypts the entire state and plan files using a pluggable key provider, but individual sensitive variables are not encrypted as their own primitive — sensitive values are typically fetched at runtime from a secrets store such as HashiCorp Vault or AWS Secrets Manager.

    Policy as code

    Pulumi Policies is open source and free. Policies can be written in Python, TypeScript, or Open Policy Agent Rego, and Pulumi Cloud adds centralized management, policy groups, and enforcement across stacks. Pulumi Cloud commercial plans also include Pulumi-maintained policy packs for common compliance frameworks (CIS, HITRUST, NIST, and PCI DSS), so teams don’t have to author and maintain those rules themselves. OpenTofu has no built-in policy-as-code feature; teams typically reach for external tools such as Open Policy Agent or Checkov to evaluate plan output as a separate step.

    Modularity and reuse

    OpenTofu modules are units of HCL referenced from a local path, a Git URL, or a registry. Modules compose within HCL. Pulumi’s Component Resources are runtime objects that can share helpers and types with the rest of your program, with explicit parent/child relationships, so a component and the resources inside it form a coherent unit in plan output, deletion, and state. Components can be authored in one language and consumed from any other supported language by publishing them as a Pulumi Package. Pulumi can also consume OpenTofu modules directly, automatically installing and invoking OpenTofu to execute them — useful for teams that have invested heavily in module libraries and want to keep using them while moving to Pulumi.

    Automation API

    The Automation API lets a host application drive Pulumi without shelling out to the CLI. Practical uses include embedding stack creation in a SaaS product, building an internal developer platform that provisions environments per team or per branch, generating ephemeral preview environments from CI, and orchestrating cross-cloud deployments where each step runs as part of a larger workflow. OpenTofu is invoked through the tofu CLI and does not provide an equivalent embeddable SDK; programmatic use means shelling out to the CLI and parsing its output.

    When to choose Pulumi vs. OpenTofu

    Choose Pulumi when you:

    1. Want to write infrastructure in a general-purpose language with the testing frameworks, package managers, and IDE tooling that already exist in that ecosystem.
    2. Need an embeddable SDK (Automation API) to drive deployments from a host application — internal developer platforms, SaaS products, or ephemeral preview environments per pull request.
    3. Want first-class encrypted secrets with pluggable KMS providers and per-stack encryption keys.
    4. Want a single managed offering (Pulumi Cloud) that covers state, RBAC, audit logs, policy management, and remote runs.

    Choose OpenTofu when you:

    1. Want a fully open-source, vendor-neutral IaC tool governed by an independent foundation, with no commercial tier from the project itself.
    2. Want the engine itself under MPL 2.0 and community governance, rather than depending on a vendor-operated control plane for state, runs, and policy.
    3. Prefer to assemble managed-state and collaboration features from third-party services (Spacelift, env0, Scalr) rather than buying them from a single vendor.

    An existing investment in HCL, modules, and team expertise is no longer a reason on its own. Pulumi runs HCL as a first-class language with OpenTofu-compatible provider resolution, executes your existing OpenTofu modules, and can back your OpenTofu state without any change to your configurations. The two can also coexist — see Adoption.

    Adoption: coexistence, conversion, and import

    There are several common paths for adopting Pulumi alongside or in place of OpenTofu, and they can be combined:

    1. Use OpenTofu alongside Pulumi. A Pulumi program can reference an existing OpenTofu state file and read its outputs through terraform.state.getLocalReference or terraform.state.getRemoteReference (both functions live in the terraform package and work with OpenTofu state). Pulumi can also execute existing OpenTofu modules directly — Pulumi auto-installs and invokes OpenTofu to run the module — which lets teams keep using their module libraries while adopting Pulumi for new work.
    2. Use Pulumi Cloud as your OpenTofu state backend. Pulumi Cloud implements the Terraform remote backend API, which the tofu CLI speaks, so adding a standard backend "remote" block and running tofu init -migrate-state is the only change. Plans and applies then run on Pulumi Cloud by default, with approval gates on VCS-triggered applies, and the stack gets encrypted state, update history, state locking, RBAC, policy enforcement, and Resource Search.
    3. Write new projects in HCL on the Pulumi engine. Pulumi HCL takes your .tf files as-is with runtime: hcl, resolving providers from the OpenTofu registry just as OpenTofu does.
    4. Convert HCL with pulumi convert. pulumi convert --from terraform translates HCL into a Pulumi program in the language of your choice. The same flag handles both Terraform and OpenTofu HCL — there is no separate --from opentofu flag, because the configuration language is the same.
    5. Import existing resources. pulumi import and the import resource option bring already-provisioned resources under Pulumi management and generate the corresponding code in your chosen language. pulumi import --from hcl <state-file> does this in bulk: it reads an OpenTofu or Terraform state file and adopts the resources it describes into Pulumi state.

    For a complete walkthrough including coexistence patterns and conversion, see Migrating from Terraform to Pulumi — the same guide applies to OpenTofu.

    Frequently asked questions

    Is OpenTofu the same as Terraform?

    OpenTofu was forked from Terraform 1.6 in 2023 after HashiCorp changed Terraform’s license from MPL 2.0 to the Business Source License. The two projects share the HCL configuration language and a largely overlapping provider ecosystem, but they have since diverged: OpenTofu is governed by the Linux Foundation and has added features such as state encryption that Terraform does not have, while Terraform has continued to ship its own new features. For most existing configurations, OpenTofu is a drop-in replacement, but the projects are not identical.

    Can Pulumi use existing OpenTofu providers and modules?

    Yes. The Any Terraform Provider feature generates a typed Pulumi SDK from any provider in the OpenTofu or Terraform registry by running pulumi package add terraform-provider <name>. Pulumi can also execute existing OpenTofu modules as components inside a Pulumi program — Pulumi auto-installs OpenTofu and invokes it to run the module.

    Can I write Pulumi programs in HCL?

    Yes. Pulumi HCL is a first-class Pulumi language: set runtime: hcl in Pulumi.yaml and keep your .tf files. It runs valid OpenTofu configurations, with a short list of documented exceptions, and unqualified provider sources resolve against the OpenTofu registry and are bridged automatically — the same behavior you get from tofu. Prefix a source with pulumi/ to use a native Pulumi provider instead. Requires Pulumi CLI 3.256.0 or later.

    Can I keep running OpenTofu and store state in Pulumi Cloud?

    Yes, with no change to your configurations. Pulumi Cloud implements the Terraform remote backend API that the tofu CLI speaks, so you add a standard backend "remote" block and run tofu init -migrate-state. Stacks created through the CLI run plans and applies on Pulumi Cloud by default, VCS-triggered applies wait for manual approval, and you get encrypted state, update history, state locking, RBAC, policy enforcement, and Resource Search while continuing to use tofu day-to-day.

    How do I migrate from OpenTofu to Pulumi?

    You have four options that can be combined: run your existing .tf files as-is on Pulumi HCL, convert HCL to another language with pulumi convert --from terraform (which handles OpenTofu HCL — there is no separate --from opentofu flag), bring already-provisioned resources under Pulumi management with pulumi import (including pulumi import --from hcl to bulk-import from an OpenTofu state file), or run both tools side by side until you’re ready to cut over. See the migration guide for a full walkthrough.

    Does Pulumi support OpenTofu state files?

    Yes. A Pulumi program can read outputs from an OpenTofu state file via terraform.state.getLocalReference for local state and terraform.state.getRemoteReference for remote backends. Both functions live in the terraform package and work with OpenTofu state because the state file format is shared between the two tools.

    Is Pulumi free like OpenTofu?

    The Pulumi CLI and SDKs are open source under Apache 2.0 and free to use. Pulumi Cloud has a free Individual tier and paid plans that add managed state, RBAC, audit logs, policy management, and other features for running Pulumi at organizational scale. OpenTofu itself is free under MPL 2.0; commercial managed-state and collaboration tooling is sold separately by third parties such as Spacelift, env0, and Scalr.

    Can Pulumi and OpenTofu run side by side during migration?

    Yes — and this is one of the more common adoption patterns. Pulumi can read outputs from OpenTofu state files and execute OpenTofu modules directly, so teams typically keep existing infrastructure under OpenTofu while using Pulumi for new work, then incrementally convert or import as the project allows.

    Next steps

      The infrastructure as code platform for any cloud.