Aug 25, 202610 min read

AWS CDK Alternatives in 2026

What to use when CloudFormation limits and construct abstractions get in the way

AWS CDK was a genuine step forward. Writing infrastructure in TypeScript, Python, or Go beat writing CloudFormation YAML by a wide margin, and the L2/L3 construct library made common patterns ergonomic. For AWS-only teams, CDK is still one of the better ways to manage infrastructure.

The friction shows up at the seams. CDK compiles to CloudFormation, which means you inherit CloudFormation's rollback behavior, its drift detection quirks, and its 500-resource-per-stack limit. Deploys are slow because CloudFormation is slow. The L2 constructs sometimes abstract the wrong things, leaving you reaching through escape hatches (node.defaultChild, addPropertyOverride) when the opinions don't fit. And because CDK is AWS-only, a multi-cloud strategy means running CDK plus something else.

This guide covers the realistic alternatives, from cross-cloud IaC tools to approaches that eliminate the separate-infrastructure-program model entirely.

AWS CDK Alternatives: An Overview

FeatureEncorePulumiTerraform / OpenTofuSSTServerless FrameworkAWS SAM
ApproachInfrastructure from codeIaC (imperative)IaC (HCL)IaC (CDK-based, serverless-first)IaC (config-driven)IaC (CloudFormation macro)
LanguageTypeScript / GoTypeScript, Python, Go, C#, JavaHCLTypeScriptYAML + pluginsYAML
Cloud supportAWS, GCP (provisions in your account)AWS, GCP, Azure, 150+ providersAWS, GCP, Azure, 3,900+ providersAWS onlyAWS primary, multi-cloud pluginsAWS only
Backing engineApplication model and Encore-managed deployment statePulumi engine (no CloudFormation)Terraform stateCDK → CloudFormationCloudFormationCloudFormation
Infrastructure configResource declarations in application code; deployment settings per environmentSeparate programSeparate HCL filesSeparate configSeparate YAMLSeparate YAML
State managementManaged by Encore for platform-managed resourcesManaged (Pulumi Cloud) or self-managedRemote state fileCloudFormation stacksCloudFormation stacksCloudFormation stacks
Multi-cloudAWS + GCP nativeYesYesNoLimitedNo
LicenseOpen Source (MPL-2.0)Open Source (Apache 2.0)MPL-2.0 (OpenTofu) / BSL (Terraform)Open Source (MIT)Open Source (MIT)Open Source (Apache 2.0)
Best forBackend infrastructure derived from application codeMulti-cloud, CDK-like DXTeams with existing Terraform estateServerless on AWSLambda-centric appsAWS-native serverless

Encore

Encore is relevant when a team wants the backend to declare the infrastructure it uses instead of maintaining a separate program that generates CloudFormation. Its open source Infra SDK for TypeScript and Go supplies the API, service, and infrastructure declarations that Encore reads into an application model.

An Encore declaration records a logical resource used by the application; it does not generate a CloudFormation resource. When deploying with Encore, supported resources are provisioned in AWS or GCP and their deployment settings are configured per environment. CDK can remain in place for shared or unsupported AWS infrastructure.

For teams using AI-first development workflows, the model gives agents direct context about APIs and resource usage. Type safety and static analysis catch invalid declarations during the build, and 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"; // Provisions managed Postgres (RDS in AWS production; Docker locally). const db = new SQLDatabase("orders", { migrations: "./migrations" }); // SNS topic on AWS, Pub/Sub topic on GCP. interface OrderPlaced { orderId: string; userId: string; } export const orderPlaced = new Topic<OrderPlaced>("order-placed", { deliveryGuarantee: "at-least-once", }); // Provisions EventBridge scheduled rule. new CronJob("daily-reports", { title: "Send daily reports", every: "24h", endpoint: generateReports, }); export const placeOrder = api( { method: "POST", path: "/orders", expose: true }, async (req: PlaceOrder): Promise<Order> => { const order = await db.queryRow`INSERT INTO orders ...`; await orderPlaced.publish({ orderId: order.id, userId: req.userId }); return order; }, );

The declarations above are part of the running backend and tell Encore which services use each resource. CDK constructs belong to a separate application that synthesizes and deploys CloudFormation stacks. Existing CDK stacks stay under CDK ownership unless a resource is handed over through a supported import workflow.

What you still configure

Compute, capacity, networking, backups, and regions are configured per environment. CDK remains responsible for every construct and CloudFormation stack outside Encore's application model.

Why teams choose Encore over CDK

Application and infrastructure changes stay together. A database declaration sits in the service that uses it without carrying subnets, security groups, and instance configuration into the backend source.

There is no CloudFormation stack for the application team to maintain. Encore manages the deployment state required for supported resources it provisions, including resource dependencies and updates.

Agent changes are checked against the application model. Resource declarations are type-checked and must be statically discoverable, so invalid changes fail during the build. The MCP server supplies schemas, traces, and the service graph as additional context.

Local, preview, and cloud environments use the same declarations. The SDK supplies local infrastructure during development, and preview environments include the resources declared by the application.

Observability follows the application structure. Traces, logs, metrics, and service relationships are available without adding constructs for each signal and service.

Key features

  • Application model, MCP context, and build-time guardrails for AI agents
  • Resource declarations alongside the backend code that uses them
  • Least-privilege IAM derived from service resource usage
  • Built-in tracing, logs, metrics, and generated architecture metadata
  • Deployment to AWS or GCP, plus standard Docker images for self-hosting

Good to know

Infrastructure whose topology is generated during synthesis and AWS resources without an Encore primitive can remain in CDK. Encore does not adopt a CDK construct tree or CloudFormation stack; connecting an existing resource uses an explicit, resource-specific ownership workflow.

Running Encore alongside CDK

CDK can continue to manage account configuration, VPCs, DNS, shared infrastructure, custom resources, and unsupported AWS services. Encore services connect to those resources through their normal SDKs, or a self-hosted environment maps Encore declarations to CDK-provisioned infrastructure.

Go deeper

Try Encore

Pulumi

Pulumi is the closest direct competitor to CDK. You write infrastructure in TypeScript, Python, Go, C#, or Java, and Pulumi provisions resources directly through cloud SDKs, no CloudFormation in the middle.

import * as aws from "@pulumi/aws"; const bucket = new aws.s3.Bucket("my-bucket", { versioning: { enabled: true }, }); export const bucketName = bucket.id;

Advantages over CDK:

  • Multi-cloud. Same programming model works for AWS, GCP, Azure, Kubernetes.
  • No CloudFormation. Deploys are faster and failures are more legible.
  • Richer language support. C# and Java alongside TypeScript/Python.

Tradeoffs:

  • State is managed by Pulumi Cloud (or you self-host). You're trading CloudFormation state for Pulumi state.
  • Pulumi-specific SDK per cloud, the APIs don't line up with cloud-native tooling the way CDK's do with AWS.
  • Infrastructure is still a separate program from your application.

Good fit for: teams who like CDK's programming-language approach but need multi-cloud or want to shed CloudFormation.

Terraform / OpenTofu

Terraform (HashiCorp, BSL-licensed since 2023) and OpenTofu (MPL-2.0 fork) remain the most widely-used IaC tools. HCL is its own thing, state files are a known quantity, and the ecosystem of providers is enormous.

resource "aws_s3_bucket" "main" { bucket = "my-bucket" } resource "aws_s3_bucket_versioning" "main" { bucket = aws_s3_bucket.main.id versioning_configuration { status = "Enabled" } }

Advantages over CDK:

  • Provider coverage is vast (3,900+ providers for OpenTofu).
  • HCL is declarative, which some teams prefer over imperative code for infra.
  • Large existing workforce knows it.

Tradeoffs:

  • HCL doesn't compose like a real language. Modules help; they're not the same.
  • State file management is its own discipline (remote state, locking, drift).
  • AI coding tools generate HCL less fluently than they generate TypeScript.

Good fit for: teams with existing Terraform estates or who prefer declarative configuration. See our Terraform Alternatives page for more.

SST

SST is built on top of CDK with a serverless-first opinion. It wraps CDK constructs into higher-level abstractions ("Api", "Bucket", "Table") aimed at Lambda + API Gateway + DynamoDB shaped applications.

import { StackContext, Api } from "sst/constructs"; export function API({ stack }: StackContext) { const api = new Api(stack, "api", { routes: { "GET /": "packages/functions/src/lambda.handler" }, }); stack.addOutputs({ ApiEndpoint: api.url }); }

Advantages over raw CDK:

  • Faster dev loop with live Lambda (sst dev runs your functions locally while using real AWS resources).
  • Higher-level constructs for common serverless patterns.
  • Integrated deploy story for the app + the infrastructure.

Tradeoffs:

  • AWS-only, like CDK.
  • Still backed by CloudFormation, so the underlying slowness and limits apply.
  • Strong opinions on serverless, less good for containerized or traditional-server apps.

Good fit for: teams building Lambda-heavy AWS apps who want more ergonomic abstractions than raw CDK. See our SST Alternatives for a broader take.

Serverless Framework

Serverless Framework predates both CDK and SST. It's YAML-driven with a plugin ecosystem, focused on Lambda deployments, and works with multiple clouds via plugins.

service: my-service provider: name: aws runtime: nodejs20.x functions: hello: handler: handler.hello events: - httpApi: "GET /"

Advantages over CDK:

  • YAML is accessible without learning a programming-language SDK.
  • Plugin ecosystem for non-Lambda needs.
  • Fast path from zero to a deployed function.

Tradeoffs:

  • YAML gets unwieldy at scale.
  • Plugin quality varies.
  • Serverless Inc. has shifted focus to a paid platform, which has created some community uncertainty.

Good fit for: small Lambda deployments where YAML config is enough.

AWS SAM

AWS SAM (Serverless Application Model) is AWS's official serverless IaC tool. It's a CloudFormation macro that expands shorthand SAM resources into full CloudFormation.

AWSTemplateFormatVersion: "2010-09-09" Transform: AWS::Serverless-2016-10-31 Resources: HelloFunction: Type: AWS::Serverless::Function Properties: Handler: app.handler Runtime: nodejs20.x Events: Api: Type: Api Properties: Path: / Method: get

Advantages over CDK:

  • AWS-native, always up to date with AWS services the day they launch.
  • Lightest conceptual overhead for pure Lambda apps.

Tradeoffs:

  • AWS-only, CloudFormation-backed, YAML.
  • Less ergonomic than CDK or SST once you need anything beyond a simple Lambda.

Good fit for: teams deep in AWS who want the most official, AWS-supported path.

How to Choose

Stay on CDK if:

  • You're AWS-only and your team is productive with the construct library.
  • The CloudFormation slowness and limits aren't painful enough to justify migration cost.
  • You have meaningful CDK investment already.

Move to Encore if:

  • You want to eliminate the separate-infrastructure-program pattern entirely.
  • You're on AWS or GCP and want managed defaults without assembling them yourself.
  • You want infrastructure that AI coding agents can read and modify along with the application code.

Move to Pulumi if:

  • You need multi-cloud.
  • You like CDK's language approach but want to escape CloudFormation.

Move to Terraform / OpenTofu if:

  • You have existing Terraform modules or team expertise.
  • You prefer declarative HCL over imperative code for infra.
  • You need the vast provider ecosystem.

Move to SST if:

  • You're committed to AWS serverless and want better ergonomics than raw CDK.

Stay on Serverless Framework or SAM only if you're already there and not feeling pain.

Code Comparison: A Postgres DB + Queue + API

The same system across three tools to make the difference concrete.

AWS CDK

const vpc = new ec2.Vpc(this, "Vpc"); const db = new rds.DatabaseInstance(this, "Db", { engine: rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_16 }), vpc, credentials: rds.Credentials.fromGeneratedSecret("admin"), }); const queue = new sqs.Queue(this, "Queue"); const api = new apigw.RestApi(this, "Api"); // ...plus Lambda definitions, VPC config, IAM roles, and wiring

Plus a separate application program that reads env vars at runtime to find the DB and queue.

Pulumi

const db = new aws.rds.Instance("db", { engine: "postgres", instanceClass: "db.t3.micro", allocatedStorage: 20, }); const queue = new aws.sqs.Queue("queue"); // ...plus Lambda and API Gateway, same ballpark as CDK

Same shape, different engine under the hood.

Encore

const db = new SQLDatabase("orders", { migrations: "./migrations" }); const queue = new Topic<OrderEvent>("order-events", { deliveryGuarantee: "at-least-once", }); export const placeOrder = api( { method: "POST", path: "/orders", expose: true }, async (req: PlaceOrder): Promise<Order> => { const order = await db.queryRow`INSERT INTO orders ...`; await queue.publish({ orderId: order.id }); return order; }, );

That's the whole thing. The infrastructure and the application are the same program. There's no IAM wiring because Encore applies least-privilege automatically based on what each service accesses.

Getting Started

# Encore brew install encoredev/tap/encore encore app create my-app --example=ts/empty cd my-app && encore run # Pulumi curl -fsSL https://get.pulumi.com | sh pulumi new aws-typescript # Terraform / OpenTofu brew install opentofu tofu init
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