Aug 25, 202611 min read

Pulumi Alternatives in 2026

What to use when you want infrastructure without separate config programs

Pulumi improved on Terraform in a real way by letting teams write infrastructure in TypeScript, Python, or Go instead of HCL. You get full IDE support, type checking, and the ability to use loops and conditionals that actually work the way you'd expect. For a lot of teams, that's been enough.

The friction is in what didn't change. You're still writing infrastructure configuration in a separate program from your application code, and stack state still exists whether you use Pulumi Cloud or a self-managed backend. Teams that adopted Pulumi to escape Terraform's authoring limitations can find that the ownership and deployment workflow remains similar, just with a more expressive language.

Most Pulumi alternatives are other IaC tools with different tradeoffs on language, cloud support, or state management. This guide covers those, plus an application-driven approach where the team does not maintain a separate infrastructure program for supported backend resources.

Pulumi Alternatives: An Overview

FeatureEncoreTerraformOpenTofuAWS CDKSSTCrossplane
ApproachInfrastructure from codeIaC (HCL)IaC (HCL)IaC (constructs)IaC (serverless-first)IaC (Kubernetes-native)
LanguageTypeScript / GoHCLHCLTypeScript, Python, Go, Java, C#TypeScriptYAML (K8s manifests)
State managementManaged by Encore for platform-managed resourcesRemote state fileRemote state fileCloudFormation stacksPulumi (managed or self-hosted)Kubernetes etcd
Cloud supportAWS, GCP (provisions in your account)AWS, GCP, Azure, 6,000+ providersAWS, GCP, Azure, 6,000+ providersAWS onlyAWS onlyAWS, GCP, Azure via providers
Infrastructure configResource declarations in application code; deployment settings per environmentSeparate HCL filesSeparate HCL filesSeparate program filesSeparate config filesSeparate YAML manifests
Learning curveTypeScript or Go SDKMedium (HCL)Medium (HCL)Medium (CDK constructs)Medium (Pulumi under the hood)High (Kubernetes + CRDs)
AI agent supportMCP server, infra in same code agents readLimitedLimitedLimitedLimitedNone
Vendor lock-inSDK migration required; Docker export availableDepends on providers and modulesDepends on providers and modulesAWS and CloudFormationAWS and PulumiKubernetes control plane
Best forBackend infrastructure derived from application codeMulti-cloud IaC with a broad ecosystemTerraform-compatible IaC with open-source governanceAWS-only shopsServerless on AWSKubernetes platform teams

Encore

Encore is relevant when the friction comes from maintaining an infrastructure program and stack state alongside the backend. Its open source Infra SDK for TypeScript and Go declares the APIs, services, and supported infrastructure used by the application. Encore reads those declarations into an application model for local development and deployment.

Pulumi resources describe cloud infrastructure and belong to a stack. Encore resources record dependencies of the application. Capacity, networking, backups, and other deployment properties are configured separately for each environment.

The application model is also useful for AI-first development workflows. Agents can see APIs and resource relationships together, while type safety and static analysis provide build-time guardrails. Deployment-specific settings such as sizing, networking, and backups stay outside the application code agents edit.

import { api } from "encore.dev/api"; import { SQLDatabase } from "encore.dev/storage/sqldb"; import { Topic } from "encore.dev/pubsub"; import { CronJob } from "encore.dev/cron"; // RDS on AWS, Cloud SQL on GCP, Docker Postgres locally. const db = new SQLDatabase("orders", { migrations: "./migrations" }); // SNS on AWS, Pub/Sub on GCP, in-memory locally. const orderEvents = new Topic<OrderEvent>("order-events", { deliveryGuarantee: "at-least-once", }); export const createOrder = api( { method: "POST", path: "/orders", expose: true, auth: true }, async (req: CreateOrderRequest): Promise<Order> => { const order = await db.queryRow` INSERT INTO orders (customer_id, total) VALUES (${req.customerId}, ${req.total}) RETURNING *`; await orderEvents.publish({ orderId: order!.id, total: order!.total }); return order!; } ); // EventBridge on AWS, Cloud Scheduler on GCP. const cleanup = new CronJob("daily-cleanup", { title: "Clean up expired orders", schedule: "0 2 * * *", endpoint: cleanupExpiredOrders, });

The SQLDatabase, Topic, and CronJob declarations are used by the backend itself. Encore analyzes those references to determine which services use each resource and provisions the cloud implementation configured for the environment. A Pulumi program describes that implementation directly and records it in stack state.

What you still configure

Capacity, networking, backups, regions, and compute settings are configured per Encore environment. Pulumi configuration remains the source of truth for every resource Pulumi continues to own.

Why teams choose Encore over Pulumi

Application and infrastructure changes stay together. A database or topic is declared in the service that uses it, so the resource and the feature can be reviewed in the same pull request.

The application team does not manage stack state for supported resources. Encore rebuilds the application model from source and manages the deployment state required for resources it provisions.

Agents get guardrails and application context. Resource declarations are type-checked and must be statically discoverable, so invalid changes fail during the build. The MCP server also exposes schemas, traces, and the service graph.

Each pull request can include a working backend environment. Preview environments use the same declarations as local development and production, including databases, topics, and cron jobs.

Observability follows the application structure. Traces, logs, metrics, and service relationships are available without defining a separate observability stack for each service.

Key features

  • Application model, MCP context, and build-time guardrails for AI agents
  • Resource declarations in the backend code that uses them
  • No application-infrastructure state file for the team to store or lock
  • Built-in tracing, logs, metrics, and generated architecture metadata
  • Standard Docker images and self-hosted infrastructure mappings

Good to know

Encore primitives must be statically discoverable, so there is no equivalent to creating resources through loops or runtime control flow. Unsupported and dynamically generated infrastructure can remain in Pulumi. Encore also does not consume Pulumi state; connecting an existing physical resource requires a resource-specific workflow.

Running Encore alongside Pulumi

Pulumi can manage organization-level, shared, unsupported, and dynamically generated infrastructure alongside Encore. Supported existing resources use Encore's resource-specific import workflows, while self-hosted environments can map Encore declarations to infrastructure provisioned by Pulumi.

Go deeper

Try Encore

Use the quick start guide to build locally, or book a 1:1 intro for a walkthrough.


Terraform

Terraform is the tool Pulumi was designed to replace, and yet some teams go back. If your frustration with Pulumi is about pricing or the complexity of Pulumi's SDK, Terraform's ecosystem is larger, the community knowledge base is deeper, and the learning resources are more abundant. HCL is less expressive than TypeScript, but it's also more predictable. What you write is what you get.

Terraform's provider ecosystem covers 6,000+ providers through the registry, far beyond what any other tool offers. For teams managing infrastructure across multiple clouds and SaaS providers, that breadth is hard to match.

resource "aws_db_instance" "orders" { identifier = "orders" engine = "postgres" engine_version = "16" instance_class = "db.t4g.micro" db_name = "orders" username = "app" password = var.db_password }

Key features

  • 6,000+ providers covering AWS, GCP, Azure, and thousands of SaaS services
  • Mature ecosystem with extensive modules, tutorials, and community support
  • HCL is declarative and predictable
  • Terraform Cloud / HCP Terraform for managed state and runs
  • Import existing infrastructure
  • Plan/apply workflow with drift detection

Good to know

Going from Pulumi back to Terraform means giving up real programming languages for HCL, which is a meaningful step backward in expressiveness. State management, the two-codebase problem, and the coordination overhead between infrastructure and application changes all remain. IBM's acquisition of HashiCorp and the BSL license change are also worth considering if licensing matters to your organization.


OpenTofu

OpenTofu is the open-source fork of Terraform maintained by the Linux Foundation. If you're considering Terraform but the BSL license is a concern, OpenTofu gives you the same HCL, the same providers, and the same workflow under MPL-2.0. Your existing Terraform files work without changes.

OpenTofu has added features Terraform doesn't have: built-in state file encryption, early variable evaluation for dynamic provider configuration, and for_each on provider blocks. The provider ecosystem is fully compatible.

Key features

  • Drop-in Terraform replacement
  • Open source under MPL-2.0 (Linux Foundation stewardship)
  • State file encryption built in
  • Early variable evaluation
  • Compatible with all Terraform providers and modules

Good to know

OpenTofu solves the licensing concern with Terraform. It doesn't change the fundamental model. You're still writing HCL, managing state files, and maintaining infrastructure configuration separately from your application code. If your frustration with Pulumi was about the IaC model itself rather than the specific language, OpenTofu has the same structural limitations.


AWS CDK

AWS CDK lets you define AWS infrastructure in TypeScript, Python, Go, Java, or C#. Like Pulumi, you get real programming languages with type safety and IDE support. The key difference is that CDK synthesizes to CloudFormation templates, so the deployment model is CloudFormation's stack-based approach rather than Pulumi's graph-based state.

CDK's high-level constructs bundle common patterns. A single ApplicationLoadBalancedFargateService creates a Fargate service, load balancer, target group, security groups, and IAM roles together.

import * as cdk from "aws-cdk-lib"; import * as rds from "aws-cdk-lib/aws-rds"; import * as ec2 from "aws-cdk-lib/aws-ec2"; const vpc = new ec2.Vpc(this, "VPC"); const db = new rds.DatabaseInstance(this, "Orders", { engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_16, }), vpc, instanceType: ec2.InstanceType.of( ec2.InstanceClass.T4G, ec2.InstanceSize.MICRO ), databaseName: "orders", });

Key features

  • Define AWS resources in TypeScript, Python, Go, Java, C#
  • High-level constructs for common patterns
  • Construct Hub with community-contributed patterns
  • CDK Migrate to import existing CloudFormation stacks
  • No separate state file (CloudFormation handles state)

Good to know

CDK is AWS only. If you deploy to GCP or Azure, CDK doesn't help, and that's a step backward from Pulumi's multi-cloud support. CloudFormation's deployment model has its own limitations: stack size limits, slow rollbacks on failure, and occasional stuck resources. CDK also still requires maintaining infrastructure code separately from application code, same as Pulumi.


SST

SST is a framework for building and deploying applications on AWS. SST v3 (Ion) replaced CDK with Pulumi under the hood, which means SST is less a Pulumi alternative and more a higher-level layer on top of it. If your frustration with Pulumi is about the amount of boilerplate you write rather than the model itself, SST's components reduce that significantly.

SST's standout features are live Lambda development with breakpoint debugging and its Console for inspecting deployed resources.

// sst.config.ts export default $config({ app(input) { return { name: "orders", home: "aws" }; }, async run() { const db = new sst.aws.Postgres("OrdersDB", { scaling: { min: "0.5 ACU", max: "2 ACU" } }); const api = new sst.aws.Function("API", { handler: "src/api.handler", link: [db], url: true, }); return { url: api.url }; }, });

Key features

  • High-level components that reduce AWS boilerplate
  • Live Lambda development with local breakpoint debugging
  • SST Console for resource inspection
  • Link system for type-safe resource bindings
  • Built on Pulumi with access to all Pulumi providers

Good to know

SST uses Pulumi under the hood, so you're not escaping Pulumi's state management or deployment model. You still need a Pulumi state backend. SST is AWS-only and primarily designed for serverless workloads. If you're leaving Pulumi because of the IaC model, SST doesn't change that. If you're leaving because Pulumi's SDK is too low-level for AWS work, SST is a reasonable step up.


Crossplane

Crossplane manages cloud infrastructure through Kubernetes custom resources. You define infrastructure as Kubernetes manifests and Crossplane controllers reconcile those manifests against your cloud provider. If your team has standardized on Kubernetes and wants to manage all infrastructure through kubectl and GitOps workflows, Crossplane fits that model.

Key features

  • Kubernetes-native infrastructure management
  • AWS, GCP, Azure support via provider packages
  • Compositions for higher-level abstractions
  • GitOps-compatible (works with Argo CD, Flux)
  • CNCF graduated project

Good to know

Crossplane requires a running Kubernetes cluster, which is a significant prerequisite. The YAML manifests are verbose, provider coverage varies, and debugging reconciliation failures requires understanding both Kubernetes and cloud provider APIs. Moving from Pulumi's TypeScript to Crossplane's YAML is a step backward in developer experience. Crossplane makes sense for platform teams that have bet on Kubernetes as their control plane. For application developers, it adds complexity.


How to choose

Teams leaving Pulumi are usually frustrated by one of three things: the pricing, the operational overhead of state management, or the realization that writing infrastructure in TypeScript is still writing infrastructure.

If the pricing is the issue but the IaC model works for you, Terraform or OpenTofu get you back to a tool with no per-resource fees. You give up TypeScript for HCL, but the ecosystem is larger and the community support is deeper. OpenTofu adds the benefit of open-source governance.

If you want to stay in TypeScript on AWS but want less boilerplate, SST is a higher-level layer on top of Pulumi that reduces the configuration you write. AWS CDK is the alternative if you prefer CloudFormation's deployment model over Pulumi's.

If Kubernetes is your control plane for everything, Crossplane extends that model to cloud infrastructure. It makes sense for platform teams, not application developers.

If the IaC model itself is the frustration, with state files, separate infrastructure programs, and the coordination overhead between infrastructure and application changes, every tool on this list except Encore still requires that. Pulumi made the authoring experience better by using real languages, but the operational model is the same.

Encore removes the separate infrastructure program for the backend resources represented by its primitives. The application team declares those resources in code, while deployment settings and managed infrastructure state remain per environment. Pulumi can continue to own everything outside that model. For teams evaluating that boundary, Coming from Pulumi covers state, imports, coexistence, and an incremental workflow.

Install Encore
$ brew install encoredev/tap/encore &&
$ encore app create
Copy

Ship without waiting on Terraform

Encore lets developers and agents define application infrastructure directly in code, then automatically provisions it from local development to production in your AWS or GCP account.

~/orders — claude
Claude Code
Claude Code v2.1.180Opus 4.8 · Encore MCP connected~/orders
Infra from codereading the code…
SQLDatabaseorders · postgres
Topicorders · pub/sub
Bucketdeclared in code
not running yet