Pulumi and Terraform are both infrastructure as code tools. Each one creates and updates cloud resources from code, previews changes before applying them, and tracks what it manages in state. The core difference is the language: Terraform uses HCL, a configuration language built for infrastructure, while Pulumi runs programs written in TypeScript, JavaScript, Python, Go,.NET, or Java, plus YAML, and can now run HCL as well.
Both tools work toward a desired end state: you describe what should exist, and the engine works out what to create, change, or delete. The differences show up in how teams write, test, and share that code, how secrets are stored, and what licensing and hosting look like as the team grows.
Pulumi vs Terraform at a Glance
- Language: Terraform uses HCL. Pulumi uses general-purpose languages and YAML, and can run existing HCL configurations.
- State: Terraform writes a state file that you store and lock in a backend such as S3, Azure Storage, Google Cloud Storage, or HCP Terraform. Pulumi uses Pulumi Cloud for state by default and also supports self-managed backends such as S3, Azure Blob Storage, Google Cloud Storage, or a local directory.
- Secrets: Pulumi encrypts secret values in state by default, with per-stack keys and optional cloud KMS. Terraform hides sensitive values in output, but stores them unencrypted in state, so the backend itself must be protected.
- Preview and apply: Terraform uses
terraform planandterraform apply. Pulumi usespulumi previewandpulumi up.
- Drift: Terraform shows drift with
terraform plan -refresh-only. Pulumi usespulumi refresh.
- Providers: The Terraform Registry has the largest provider and module ecosystem. Pulumi has its own native providers for several platforms and can adapt any Terraform provider.
- Testing: Terraform has
terraform testwith test files written in HCL. Pulumi programs use the language's own test frameworks, such as Jest, pytest, or Go's testing package.
- Licensing: Terraform has been under the Business Source License since 2023, and OpenTofu is its open-source fork under MPL 2.0. The Pulumi CLI and SDKs are open source under Apache 2.0, and Pulumi Cloud is a commercial service with a free tier.
Language: HCL or a Programming Language
HCL is deliberately limited. It has variables, modules, for_each, count, conditionals, and built-in functions, and not much more. That constraint is the point: a reviewer who does not write software every day can read a Terraform diff and understand what will change. The cost is that complex logic, such as generating resources from nested data or sharing typed abstractions, gets awkward fast.
Pulumi gives you a full programming language. Loops, functions, classes, package managers, type checking, and editor autocomplete all work the way developers expect. Component resources let you package a pattern, such as a service with its load balancer, alarms, and IAM roles, as a library other teams import. The Automation API goes further and lets you run Pulumi from inside your own software, which is how some platform teams build self-service environment tools.
The trade-off is review. A general-purpose language allows clever code, and clever infrastructure code is hard to review under pressure. Teams that pick Pulumi tend to write conventions for how much logic belongs in a program, the same way they do for application code.
State and Secrets
Both tools keep a record of every resource they manage, and both need that record to be accurate. With Terraform, the state file is yours: you choose the backend, turn on locking so two runs cannot write at once, and restrict access, because state can hold database passwords, keys, and other sensitive values in plain text. OpenTofu added client-side state encryption in version 1.7, which closes part of that gap for teams using it.
Pulumi's default is to keep state in Pulumi Cloud, which handles storage, locking, and history. Secrets marked as secret are encrypted in state and stay encrypted in output, using a per-stack key or a KMS key you provide from AWS, Azure, Google Cloud, or HashiCorp Vault. Teams that cannot use a hosted service can point Pulumi at their own object storage instead.
Providers and Ecosystem
Terraform's biggest advantage is reach. Nearly every cloud, SaaS platform, and infrastructure vendor publishes a Terraform provider, the public registry has modules for most common patterns, and vendor documentation often shows Terraform examples first. That also means more answered questions, more engineers who already know it, and an easier time hiring.
Pulumi narrows most of that gap. Many Pulumi providers are bridged from Terraform providers, any Terraform provider can be adapted, and Pulumi can consume existing Terraform modules directly from a program. It also publishes native providers generated from cloud APIs, including Kubernetes, Azure Native, and AWS Cloud Control, which can pick up new platform features quickly.
Testing and Policy
Terraform supports terraform validate for syntax and terraform test for test files that run plans or applies and check the results. Policy checks usually run on the plan, in HCP Terraform with Sentinel or in a separate pipeline step.
Pulumi programs can be unit tested with mocked resources in the language's normal test runner, which application developers already know, and integration tested by deploying short-lived stacks. Pulumi also supports policy packs written in TypeScript or Python that run during preview and update.
Which Should You Choose?
Choose Terraform or OpenTofu when infrastructure is owned by a platform or operations team, you want a constrained language that is easy to review, you depend on community modules, or most of your existing estate is already in HCL. Choose OpenTofu over Terraform if an open-source license or built-in state encryption matters to you.
Choose Pulumi when infrastructure is written by application developers in the same language as the application, when you need real abstractions or want to embed provisioning in your own tools, or when encrypted secrets in state by default is a requirement.
Either choice works for most teams. The trouble starts when a company ends up with both, plus resources created in a console, and no single place to see what exists, who owns it, and which tool is supposed to manage it.
Switching From One to the Other
Moving from Terraform to Pulumi has well-worn paths: run existing .tf files with Pulumi's HCL support, convert HCL into a Pulumi program with pulumi convert --from terraform, or bring already-provisioned resources under Pulumi with pulumi import. During a gradual move, a Pulumi program can read outputs from Terraform state.
Moving from Pulumi to Terraform or OpenTofu has no official converter. The practical route is to write the HCL, adopt the existing resources with import blocks instead of recreating them, let terraform plan -generate-config-out draft configuration for imported resources, and compare plans until they show no unexpected changes. The same approach works for resources that were never in any tool; the guide to generating Terraform from existing AWS resources walks through it.
Seeing What Exists, Whichever Tool You Use
Picking an engine settles how new infrastructure gets written. It does not tell you what is already running outside of it: resources created in the console, by scripts, or by a stack nobody maintains anymore. ops0 discovery is read-only and works from the cloud provider APIs across AWS, Google Cloud, Azure, Oracle Cloud, and Kubernetes, not from one tool's state, so it shows what is running regardless of which tool created it. See multi-cloud discovery for how that inventory is built.
For teams that standardize on Terraform or OpenTofu, ops0 generates code for existing resources, imports them instead of recreating them, and runs each change through plan review, policy checks for CIS, SOC 2, HIPAA, ISO 27001, ISO 27002, and GDPR, and an approval step where the person who starts a deployment cannot approve it.
Is Pulumi better than Terraform?
Neither is better in general. Terraform suits platform and operations teams that want a constrained, reviewable language and the largest provider ecosystem. Pulumi suits teams where application developers write infrastructure in the same language as their code, or where encrypted secrets in state and real abstractions matter.
Is Pulumi declarative or imperative?
Both, in a sense. You write Pulumi programs in imperative languages, but running the program produces a declarative description of the desired resources. The Pulumi engine compares that with state and works out what to create, update, or delete, the same way Terraform does with HCL.
Is Pulumi free to use?
The Pulumi CLI and SDKs are open source under Apache 2.0 and free. Pulumi Cloud, the hosted service for state, secrets, and team features, has a free tier, and paid editions add collaboration, access control, audit logs, and policy management. You can also self-manage state in your own storage.
Can Pulumi use Terraform providers and modules?
Yes. Many Pulumi providers are bridged from Terraform providers, any Terraform provider can be adapted for Pulumi, and Pulumi programs can consume existing Terraform modules directly.
How do I migrate from Terraform to Pulumi?
Run existing .tf files with Pulumi's HCL support, convert HCL into a Pulumi program with pulumi convert --from terraform, or import already-provisioned resources with pulumi import. Move one stack at a time and compare previews until they show no unexpected changes.
- Pulumi vs. Terraform: Pulumi. Languages, providers, state, secrets, testing, and licensing from Pulumi's side.
- State and backends: Pulumi. Pulumi Cloud and self-managed state backends.
- Secrets handling: Pulumi. Encryption of secret values in state and per-stack keys.
- Migrating from Terraform to Pulumi: Pulumi. Conversion, import, and coexistence options.
- State: HashiCorp. Purpose of Terraform state, backends, and locking.
- Tests: HashiCorp. The terraform test framework.
- OpenTofu FAQ: OpenTofu. Licensing and governance of the open-source fork.