Infrastructure as Code: Terraform vs Pulumi vs CDK
Infrastructure as code is the practice of defining cloud resources in version controlled files rather than through manual console clicks. Terraform, Pulumi, and AWS CDK are the three dominant tools for doing this, each with a different philosophy: Terraform uses its own declarative language, Pulumi uses general purpose programming languages, and CDK uses TypeScript or Python to generate CloudFormation.
What you need to know
- Terraform is the default choice for teams that need coverage across multiple clouds, a large provider ecosystem, and broad community support. HCL is a tradeoff: simpler for infrastructure descriptions, but limited for complex logic.
- Pulumi is the right choice when your team finds HCL limiting and wants to write real programming logic against cloud APIs. It supports TypeScript, Python, Go, and others.
- AWS CDK is a strong choice for shops that run only on AWS and want to write TypeScript or Python and leverage the L2 construct library, which provides sensible defaults for complex resources like ECS services and RDS clusters.
- State management is the operational overhead that all three tools require. The tooling for managing and protecting state differs and should be evaluated as part of the adoption decision.
- The switching cost between these tools is significant. Choose based on your team's existing strengths and long term cloud strategy, not hype cycles.
The core argument
The IaC decision is really a language decision wrapped in an infrastructure question. All three tools can provision the resources you need. The practical differences are in how you express your intent, how readable the result is for a team member who did not write it, and how well the tool handles the complexity of your environment six months from now when the infrastructure has grown substantially.
Terraform's HCL is built for infrastructure descriptions specifically. It is readable, declarative, and forces a clean separation between resource definitions and logic. The limitation is that HCL is not a general purpose language, so when you need conditional logic, dynamic resource counts, or shared abstractions, you end up in module and workspace patterns that become complex. The state management workflow is also its own operational responsibility: you need a remote backend, locking, and careful discipline around plan and apply commands in a team environment. That said, the provider ecosystem is unmatched, and if you are working with more than one cloud provider or many third party services, Terraform covers the surface area that Pulumi and CDK do not.
Pulumi and CDK both use real programming languages, which means the full capability of those languages is available for expressing infrastructure: typed interfaces, loops, functions, and libraries. In my experience, teams that already know TypeScript adopt CDK or Pulumi faster than they learn HCL, and they end up with infrastructure code that follows the same conventions as their application code. CDK specifically has a strong advantage on AWS: the L2 constructs package sensible defaults for complex resources and significantly reduce the boilerplate compared to writing CloudFormation directly. If your team runs only on AWS and leads with TypeScript, CDK is the most productive path. If you need to support multiple clouds or want to avoid CloudFormation's limitations, Pulumi gives you the same language benefits without being locked into AWS.
Common mistakes
Storing Terraform state locally. Local state works for solo experimentation but is unusable for a team. Set up remote state in S3 with DynamoDB locking before the first shared infrastructure apply. Retrofitting remote state after the fact is a painful migration.
Not using workspaces or stacks for environment separation. Production and staging infrastructure should live in separate state contexts. A single Terraform workspace or Pulumi stack covering multiple environments is a blast radius problem waiting to happen.
Importing existing resources instead of rebuilding them with IaC. The import workflow is useful for adopting IaC incrementally, but importing complex resources that were created manually often results in state that is difficult to reason about. Rebuild new resources with IaC where possible and import only what you cannot recreate.
Abstracting with modules too early. Custom Terraform modules and CDK constructs add complexity. Build flat, explicit configurations for the first version. Abstract when the repetition is clear and stable, not in anticipation of hypothetical reuse.
Not pinning provider and tool versions. An infrastructure apply that uses a different provider version than the one that originally created the resource can produce unexpected diffs or errors. Pin provider versions in the configuration and update them deliberately.
Where to start
Pick the tool based on your team's language affinity and cloud targets. AWS only and TypeScript team: CDK. Multiple clouds or heavy GCP/Azure use: Terraform. Team that knows Python well and wants flexibility: Pulumi. Do not pick the tool you read about last week; pick the one your team will maintain.
Set up remote state before writing any real infrastructure. For Terraform: S3 bucket plus DynamoDB table, configured in the backend block before the first apply. For Pulumi: the Pulumi Cloud backend or a self hosted option backed by S3. This step is required for team use.
Start with the networking layer. VPC, subnets, security groups, and IAM roles are the foundation everything else depends on. Getting these right in IaC first establishes the pattern for the rest of the infrastructure.
Related reading
- Docker Compose to Kubernetes: When to Make the Jump
- CI/CD Pipeline Design That Scales Past Ten Engineers
- Cloud Cost Optimization: A Practical Checklist
- Monorepo vs Multi-Repo: A Decision Framework
FAQ
Frequently asked
- Which IaC tool has the largest ecosystem in 2026?
- When does Pulumi make more sense than Terraform?
- Is AWS CDK only useful for AWS?
- How does Terraform state management work and why does it matter?
- Can I mix IaC tools in the same project?
Author
The person behind Yashveer Labs
Yashveer Singh, founder of Yashveer Labs. I build full stack systems for clients who care that the thing actually works two years later, not just on launch day. The arc I am on points at machine learning, AI engineering, and cybersecurity. Everything I write here comes from the codebase, not from a content brief. That is the difference and it shows.