Pulumi vs AWS CDK vs Crossplane — Modern IaC Tools 2026
Terraform is the default but Pulumi, AWS CDK, and Crossplane are growing fast. Here's when each makes sense and how they compare to each other.
Terraform is the IaC standard. But Pulumi, AWS CDK, and Crossplane are each winning in specific scenarios. Here's the honest comparison.
Why Look Beyond Terraform?
Terraform is great. But it has real limitations:
- HCL is not a programming language — loops, conditionals, functions are awkward
- Testing infrastructure code is hard
- Sharing and reusing code (modules) is verbose
The alternatives address these specifically.
Pulumi
Write infrastructure in Python, TypeScript, Go, C#, or Java. Full programming language — real loops, conditionals, functions, testing frameworks.
Example: EKS Cluster in Python
import pulumi
import pulumi_aws as aws
import pulumi_eks as eks
# Real Python — use variables, loops, functions naturally
env = pulumi.get_stack() # "dev", "staging", "prod"
vpc = aws.ec2.Vpc(
f"{env}-vpc",
cidr_block="10.0.0.0/16",
enable_dns_hostnames=True,
tags={"Environment": env}
)
# Python dict comprehension — try this in HCL
subnet_ids = []
for i, az in enumerate(["us-east-1a", "us-east-1b", "us-east-1c"]):
subnet = aws.ec2.Subnet(
f"{env}-subnet-{i}",
vpc_id=vpc.id,
cidr_block=f"10.0.{i}.0/24",
availability_zone=az,
map_public_ip_on_launch=True
)
subnet_ids.append(subnet.id)
cluster = eks.Cluster(
f"{env}-cluster",
vpc_id=vpc.id,
subnet_ids=subnet_ids,
instance_type="t3.medium",
desired_capacity=2,
min_size=1,
max_size=10,
)
pulumi.export("kubeconfig", cluster.kubeconfig)Pulumi Strengths
- Real programming language — Python/TypeScript testing frameworks, type safety, IDE support
- Multi-cloud — same SDK for AWS, GCP, Azure, Kubernetes, 100+ providers
- Pulumi Cloud — managed state backend (free tier available)
- Converts Terraform —
pulumi convert --from terraformmigrates existing HCL
Pulumi Weaknesses
- Smaller community than Terraform (but growing fast)
- Pulumi Cloud required for team features (or self-host backend)
- Language-specific bugs can be subtle
Best for
- Teams who prefer writing Python/TypeScript over HCL
- Complex infrastructure with lots of conditional logic
- Teams who want to test infrastructure code with pytest/jest
AWS CDK (Cloud Development Kit)
AWS CDK lets you define AWS infrastructure in TypeScript, Python, Java, C#, or Go. It compiles down to CloudFormation.
Example: ECS Service in TypeScript
import * as cdk from 'aws-cdk-lib';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ecsp from 'aws-cdk-lib/aws-ecs-patterns';
export class MyServiceStack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// CDK handles VPC, cluster, load balancer, IAM — all in 10 lines
new ecsp.ApplicationLoadBalancedFargateService(this, 'MyService', {
taskImageOptions: {
image: ecs.ContainerImage.fromRegistry('nginx:latest'),
containerPort: 80,
},
publicLoadBalancer: true,
desiredCount: 2,
cpu: 256,
memoryLimitMiB: 512,
});
}
}CDK Strengths
- Higher-level abstractions —
ApplicationLoadBalancedFargateServicecreates 15+ AWS resources in one construct - AWS-native — best-in-class support for every AWS service
- CDK Constructs Library — reusable community constructs
- AWS-supported — first-class AWS tooling and docs
CDK Weaknesses
- AWS-only — no multi-cloud support (CDK for Terraform exists but is different)
- CloudFormation backend means CloudFormation's quirks and limits
- Some complex scenarios need CloudFormation knowledge
Best for
- AWS-only teams who want high-level abstractions
- Teams who already use TypeScript
- When you want one construct that creates an entire service
Crossplane
Crossplane extends Kubernetes to manage cloud infrastructure. You define AWS/GCP/Azure resources as Kubernetes CRDs.
Example: RDS Database via Kubernetes YAML
# PostgreSQL RDS instance as a Kubernetes resource
apiVersion: rds.aws.upbound.io/v1beta1
kind: Instance
metadata:
name: production-db
spec:
forProvider:
region: us-east-1
instanceClass: db.t3.micro
engine: postgres
engineVersion: "15.4"
dbName: myapp
username: admin
allocatedStorage: 20
skipFinalSnapshot: true
writeConnectionSecretToRef:
namespace: default
name: db-connection # Creates K8s secret with connection stringkubectl apply -f postgres.yaml
kubectl get instance production-db
# NAME READY SYNCED AGE
# production-db True True 5mThe RDS instance shows up in kubectl get just like a pod.
Composition — Define Your Own Abstractions
# Define a "PostgresDatabase" composite resource
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xpostgresdatabases.devops.example.com
spec:
names:
kind: XPostgresDatabase
claimNames:
kind: PostgresDatabase
# ... define what fields dev teams can setNow developers request a database like this:
# Developer's request — they don't need to know AWS details
apiVersion: devops.example.com/v1alpha1
kind: PostgresDatabase
metadata:
name: my-app-db
spec:
parameters:
size: small # Platform team defines what "small" means in AWS terms
region: us-east-1Crossplane Strengths
- Kubernetes-native — same tools, same RBAC, same GitOps workflows
- Self-service platforms — developers request infrastructure without knowing AWS
- GitOps compatible — ArgoCD/Flux manage cloud resources like app manifests
- Multi-cloud — provider for AWS, GCP, Azure, and many more
Crossplane Weaknesses
- Complex setup — Crossplane + providers + compositions is significant overhead
- Kubernetes dependency — requires a running cluster
- Steep learning curve — Compositions and XRDs are powerful but complex
- Not Terraform replacement — better for platform teams, not individual DevOps
Best for
- Platform engineering teams building self-service developer portals
- Organizations standardizing on Kubernetes for everything
- Teams doing GitOps and want cloud resources in the same workflow
Head-to-Head
| Pulumi | AWS CDK | Crossplane | |
|---|---|---|---|
| Language | Python/TS/Go/C# | TS/Python/Java/C# | YAML (Kubernetes) |
| Multi-cloud | ✅ | ❌ AWS only | ✅ |
| Kubernetes native | Via provider | ❌ | ✅ Native |
| Learning curve | Medium | Medium | High |
| State management | Pulumi Cloud/S3 | CloudFormation | Kubernetes etcd |
| Best for | General IaC | AWS-heavy teams | Platform Engineering |
Choose Pulumi if you hate HCL but don't want to go Kubernetes-native.
Choose CDK if you're AWS-only and want high-level constructs.
Choose Crossplane if you're building a self-service developer platform on Kubernetes.
Keep Terraform if your team is productive with it and there's no specific pain point.
Learn all IaC tools with hands-on practice at KodeKloud — Terraform, Pulumi, and Kubernetes all have dedicated courses.
Today I Fixed
Short real fixes from production — posted daily
Stay ahead of the curve
Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.
Related Articles
Build a Complete AWS Infrastructure with Terraform from Scratch (2026)
Full project walkthrough: provision a production-grade AWS VPC, EKS cluster, RDS, S3, and IAM with Terraform. Real code, real architecture, ready to use.
HashiCorp Vault vs AWS Secrets Manager vs External Secrets Operator — Which to Use in 2026?
Comparing the top three secrets management solutions for Kubernetes and cloud environments in 2026. Pricing, features, complexity, and when to pick each.
AWS EKS Cluster Autoscaler Not Scaling — Every Fix (2026)
Your EKS Cluster Autoscaler isn't scaling up, scale-down isn't working, or nodes spin up but stay empty. Here's every cause and the exact fix.