Beyond AWS
While CDK is designed specifically for AWS (and synthesizes to CloudFormation), Pulumi is cloud-agnostic. It works with AWS, Azure, Google Cloud, Kubernetes, and hundreds of other providers — all from the same tool and the same programming model.
Think of Pulumi as the "write once, deploy anywhere" approach to IaC. The same mental model — resources, stacks, outputs — applies whether you're deploying an S3 bucket, an Azure Blob Storage container, or a Kubernetes Deployment.
Language Choice as a Feature
Pulumi's core superpower is meeting developers where they already are. You don't learn a domain-specific language like HCL or a framework-specific pattern like CDK's construct model. You write infrastructure in the language your team already uses day-to-day: TypeScript, Python, Go, C#, or Java.
This means your existing IDE (with full autocomplete and type checking), linters, formatters, and testing frameworks work directly with your infrastructure code. A Python developer can write infrastructure in Python, run pytest against it, and check it into the same repository as their application code — no context switching required.
# Pulumi Python example: Create an S3 bucket
import pulumi
import pulumi_aws as aws
bucket = aws.s3.Bucket("my-bucket",
versioning=aws.s3.BucketVersioningArgs(enabled=True),
server_side_encryption_configuration=aws.s3.BucketServerSideEncryptionConfigurationArgs(
rule=aws.s3.BucketServerSideEncryptionConfigurationRuleArgs(
apply_server_side_encryption_by_default=aws.s3.BucketServerSideEncryptionConfigurationRuleApplyServerSideEncryptionByDefaultArgs(
sse_algorithm="AES256"
)
)
)
)
pulumi.export("bucket_name", bucket.id)
How Pulumi Works Under the Hood
When you run pulumi up, the Pulumi CLI executes your program. As your code runs, every resource you instantiate (e.g., aws.s3.Bucket(...)) registers itself with the Pulumi engine. The engine compares the desired state (what your program describes) against the current state (stored in a state file) and computes a diff — exactly like Terraform's plan. It then calls the appropriate cloud APIs to reconcile the two.
This is a fundamentally different model from CDK. CDK synthesizes to a static CloudFormation template first, then CloudFormation deploys it. Pulumi's engine is always live — it evaluates your program and talks to cloud APIs directly, without an intermediate template format.
State Management
Like Terraform, Pulumi needs a state file to track which real-world resources correspond to which resources in your code. Without state, Pulumi wouldn't know whether to create a new bucket or update an existing one.
Pulumi offers two state backend options:
- Pulumi Cloud (SaaS): The default when you sign up at pulumi.com. Pulumi hosts the state, handles concurrent access locking, provides a web UI with deployment history, and supports secrets encryption. This is the easiest option for teams getting started.
- Self-Managed Backend: Store state in your own infrastructure — an S3 bucket, a GCS bucket, an Azure Blob container, or the local filesystem. This gives you full control over state storage and avoids a SaaS dependency, but you're responsible for locking, backup, and access control.
A common interview question is: "How does Pulumi differ from Terraform?" The surface answer is "Pulumi uses real programming languages." The deeper answer covers three dimensions: (1) Execution model — Pulumi runs your program live; Terraform parses HCL into a graph. (2) State — both use state files, but Pulumi's default is a hosted SaaS backend while Terraform's default is local. (3) Ecosystem — Terraform has a vastly larger provider ecosystem and community today, while Pulumi has better native language integration. Neither is universally better; the right choice depends on team skills and multi-cloud requirements.
Key Point: Pulumi's language flexibility removes the learning curve for developers transitioning from application code to infrastructure code. However, this flexibility is also a risk: a poorly structured Pulumi program with complex logic, side effects, or non-deterministic behavior can be harder to reason about than equivalent HCL. The discipline of keeping infrastructure code simple and declarative in spirit — even when using a general-purpose language — is a hallmark of mature Pulumi usage.