Terraform vs Pulumi vs CDK: Infrastructure as Code Compared

Terraform vs Pulumi vs CDK: Infrastructure as Code Compared for 2026

Managing cloud infrastructure manually is a recipe for disaster. Infrastructure as Code (IaC) tools let you define, version, and reproduce your infrastructure declaratively or programmatically. But which tool is right for your team? We used Terraform, Pulumi, and AWS CDK to manage identical production-grade infrastructure and compared the experience end-to-end across state management, language flexibility, multi-cloud deployment, and migration complexity.

Tool Overview

Terraform (HashiCorp)

The industry standard. HCL declarative language, massive provider ecosystem (3000+ providers), mature state management, and the largest IaC community. Used by 70%+ of Fortune 500 companies. Free open-source version plus paid Terraform Cloud/Enterprise for collaboration and governance.

Pulumi

Write infrastructure in real programming languages — Python, TypeScript, Go, C#, or Java. No custom DSL to learn. Pulumi converts your code into the same provider calls Terraform uses, but with the full power of a real language: loops, conditionals, functions, classes, and testing frameworks. The same code can target AWS, Azure, GCP, or Kubernetes in a single project.

AWS CDK (Cloud Development Kit)

AWS-specific IaC tool that lets you write infrastructure in TypeScript, Python, Java, or C#. CDK synthesizes your code into CloudFormation templates. Deepest AWS integration with constructs, L2/L3 abstractions, and escape hatches, but vendor-locked — cannot manage GCP, Azure, or third-party services natively.

Head-to-Head: Building a Production VPC

We built a production-grade VPC with public/private subnets across three availability zones, NAT gateways, security groups, flow logs, and an EKS cluster on each tool. The same architecture, the same constraints — only the tooling differed.

Lines of Code

Terraform: 280 lines of HCL. Pulumi (TypeScript): 140 lines. CDK: 110 lines. CDK and Pulumi win on conciseness because loops and functions eliminate repetition. Terraform’s HCL lacks native for-loops for resource block generation, requiring count or for_each meta-arguments that still result in verbose configuration.

Time to Working Infrastructure

Terraform: 45 minutes (experienced), 2 hours (new learner). Pulumi: 30 minutes (experienced), 1.5 hours (if you know TypeScript). CDK: 25 minutes (experienced), 1 hour (if you know TypeScript). Language familiarity is the biggest factor — if your team already writes TypeScript daily, Pulumi and CDK have near-zero syntax overhead.

State Management Deep Dive

State management is the backbone of any IaC tool — it maps your configuration to real-world resources and detects drift. Here is how the three tools differ at a fundamental level.

Terraform State Files

Terraform uses a state file (terraform.tfstate) that records every resource’s attributes and metadata. By default it is stored locally, but production teams use remote backends — S3 with DynamoDB locking, Terraform Cloud, or HashiCorp Consul. State locking prevents two team members from running apply simultaneously and corrupting state. Sensitive data in state requires encryption at rest and in transit. Terraform also supports state file versioning, state migration between backends, and the ‘terraform import’ command to bring existing resources under management. The downside: state files can become large (megabytes for complex deployments), and any corruption or manual editing of state can cause unrecoverable drift. Teams need strict processes around state access and backup.

Pulumi Self-Managed State

Pulumi offers managed state via Pulumi Cloud (free for individual developers) with automatic encryption, versioning, point-in-time recovery, and built-in locking. No need to configure DynamoDB tables or S3 buckets — it just works. Pulumi also supports self-managed backends: AWS S3, GCP GCS, Azure Blob Storage, or a local filesystem. The state schema is richer than Terraform’s because it stores dependency graphs and deployment metadata, enabling features like preview diffs across multiple stacks. Because Pulumi stores state server-side, every deployment is automatically recorded in the Pulumi Cloud timeline, making audit trails trivial. The trade-off: heavy reliance on Pulumi Cloud for the best experience, and the self-managed backend lacks some of the advanced features like resource search and timeline.

CDK / CloudFormation State

CDK sidesteps state management entirely by delegating to AWS CloudFormation. CloudFormation maintains a stack state file on the AWS side — you never see or touch it. Updates are handled through Change Sets, which AWS calculates by diffing the new template against the current stack. This zero-configuration approach is ideal for AWS-only teams: no backend setup, no locking configuration, no state file corruption risk. However, it comes with limitations: CloudFormation stack updates can be slow (especially for large stacks), there is a hard limit of 500 resources per stack (requiring nested stacks), and the rollback behavior on failure can be destructive — if a resource fails to create, CloudFormation may delete successfully created resources during rollback. You also lose the ability to inspect or manipulate state directly for recovery scenarios.

Programming Language Flexibility

The choice of DSL versus general-purpose language is the most opinionated difference among these tools and heavily influences team productivity.

Terraform: HCL — Purpose-Built but Limited

HashiCorp Configuration Language (HCL) is designed specifically for infrastructure. It is declarative, human-readable, and enforces a consistent structure across all providers. However, HCL lacks programming fundamentals: no if/else logic, no native loops over complex data structures, no functions for string manipulation or list comprehensions (though Terraform 1.x improved with templatefile and for expressions). Complex logic requires external data sources, null_resource workarounds, or embedding shell scripts — all of which reduce readability and testability. Teams that need dynamic infrastructure (e.g., generating 50 security group rules from a YAML config) find HCL frustratingly verbose.

Pulumi: Full Programming Language Power

Pulumi lets you use TypeScript, Python, Go, C#, Java, or YAML. This means you can use loops, conditionals, map/filter/reduce, classes, inheritance, and your entire language ecosystem. Need to generate infrastructure from a CSV file? One line of Python. Need to share infrastructure components across projects? Publish them as npm/PyPI/Go modules. Need unit tests? Write them with pytest, Jest, or Go’s testing package — no special tooling required. The Pulumi Automation API even lets you embed infrastructure operations into your application code for dynamic, on-demand cloud environments. The cost: debugging infrastructure code requires both IaC and language debugging skills, and some language-specific edge cases (e.g., async/await in TypeScript with resource dependencies) can be non-obvious.

CDK: AWS-Tuned TypeScript/ Python

CDK offers the same language flexibility as Pulumi but optimized for AWS. CDK constructs are object-oriented — you build infrastructure by composing classes (e.g., new Vpc(…) with all best practices baked in). The CDK “escape hatch” lets you drop down to raw CloudFormation when constructs don’t cover your use case. CDK also supports unit testing by asserting on the synthesized CloudFormation template — a unique approach that validates both your logic and the generated template simultaneously. However, CDK’s language support is less mature for Python and Java compared to TypeScript, and the construct ecosystem, while rich, is entirely AWS-focused.

Multi-Cloud Deployment Scenario Analysis

Most organizations eventually operate across multiple cloud providers, whether by design (avoiding lock-in, leveraging best-of-breed services) or by acquisition (inheriting existing cloud footprints).

Scenario 1: Primary AWS + Secondary GCP

Terraform is the clear winner here. A single HCL workspace can manage AWS (VPCs, EC2, RDS) and GCP (GKE, Cloud Storage, BigQuery) side by side with a unified state file. Pulumi can do the same with real-language abstraction — you can write a function that provisions equivalent resources on both clouds from shared configuration — but requires more upfront architecture. CDK cannot participate in this scenario at all.

Scenario 2: Azure + On-Premises + Edge

Terraform’s 3000+ providers cover Azure, VMware, Nutanix, Proxmox, Cloudflare, and 50+ edge/on-prem platforms. Pulumi covers most of these through its Terraform bridge but may lag behind on newer provider features. CDK is not viable here.

Scenario 3: Migrating from One Cloud to Another

Pulumi shines in migration scenarios. Because you write infrastructure in a general-purpose language, you can build abstractions that generate equivalent resources on both source and target clouds, run them in parallel during migration, and decommission the old ones — all within the same codebase and deployment pipeline. Terraform can do this with modules and workspaces but requires more manual orchestration. CDK users must completely rewrite infrastructure for the target cloud.

Scenario 4: Kubernetes + Cloud Hybrid

All three tools support Kubernetes providers. Pulumi’s Kubernetes provider is the most mature — it directly manages Kubernetes resources via the API server without needing Helm or kubectl wrappers. Terraform’s Kubernetes provider works well but often requires the Helm provider for complex charts. CDK’s Kubernetes support is limited to EKS cluster creation and basic add-ons.

Migration Cost Assessment

Switching IaC tools is a significant engineering investment. Here is what each migration path entails.

Terraform to Pulumi

Pulumi provides the terraform2pulumi converter that translates HCL to TypeScript, Python, or Go. Simple configurations convert cleanly (90%+ automatic). Complex modules with loops, dynamic blocks, and external data sources require manual rewriting. Expect 2-4 weeks for a medium-sized infrastructure (50-100 resources). The benefit: once migrated, you gain testing, code reuse, and CI/CD integration that HCL cannot offer. Risk: your team must learn both the new language and Pulumi’s resource model simultaneously.

Terraform to CDK

This is a full rewrite. Terraform’s HCL and CDK’s CloudFormation model have fundamentally different abstractions. There is no automated converter. Expect 4-8 weeks for the same 50-100 resources. CDKTF (CDK for Terraform) can intermediate — you write CDK code that generates Terraform configurations — but this adds a layer of indirection and complexity. Only worth it if your team is already CDK-heavy and wants to consolidate.

Pulumi to Terraform

Pulumi can export its state as Terraform-compatible JSON, but the conversion is lossy — Pulumi’s richer state model does not map cleanly to Terraform’s flat state file. Manual migration with terraform import is the safest route, requiring each resource to be imported individually. Expect 3-6 weeks for 50-100 resources. Consider whether you actually need to migrate — Pulumi’s Terraform bridge means you can use any Terraform provider without leaving Pulumi.

CDK to Terraform or Pulumi

Migrating away from CDK involves exporting CloudFormation templates and converting them to Terraform/Pulumi — a mostly manual process with limited tooling support. CDK constructs (L2/L3) generate complex CloudFormation that is difficult to reverse-engineer. Expect 6-10 weeks. The highest migration cost of all three paths.

Key takeaway: choose your IaC tool carefully for long-term projects. Migration costs are non-trivial, and the decision should factor not just today’s infrastructure needs but your team’s projected skill evolution and cloud strategy over the next 2-3 years.

Pricing

All three have free tiers. Terraform Cloud free for up to 5 users. Pulumi Cloud free for individuals with unlimited stacks. CDK is free (CloudFormation is free — you only pay for the AWS resources you create). Team plans: Terraform Cloud $20/user/month, Pulumi Team $50/user/month, CDK no additional cost beyond AWS.

Final Verdict

Terraform remains the safest choice for most teams — battle-tested, vast community, and unmatched provider coverage. Pulumi is the best choice for developer-heavy teams who want real programming languages and testable infrastructure. CDK is the best choice for AWS-only shops wanting the deepest platform integration. Rating: Terraform 8.5/10, Pulumi 8/10, CDK 7.5/10 (9/10 for AWS-only)

FAQ

Q: Can I migrate from Terraform to Pulumi?
A: Yes, Pulumi has a built-in terraform2pulumi converter. Most HCL translates directly (90%+ for standard patterns), though complex modules with dynamic blocks or external data sources may need manual adjustment. Pulumi can also import existing Terraform state to avoid resource recreation.

Q: Is CDK better than Terraform for AWS?
A: For AWS-only infrastructure with developer-heavy teams, CDK offers a superior experience — deeper AWS integration, constructs with best-practice defaults, and native CloudFormation state management. For multi-cloud or ops-heavy teams, Terraform remains more flexible and portable.

Q: Does Pulumi lock me into Pulumi Cloud?
A: No. While Pulumi Cloud offers the best experience (encryption, audit trails, collaboration), Pulumi also supports self-managed backends including AWS S3, GCP GCS, Azure Blob, and local filesystem. The open-source CLI works fully offline.

Q: Which tool has the best CI/CD integration?
A: All three integrate with GitHub Actions, GitLab CI, and Jenkins. Pulumi has the edge with its Automation API — you can embed infrastructure operations directly into your CI/CD pipelines as code. Terraform Cloud provides native run triggers and policy-as-code. CDK integrates natively with AWS CodePipeline and CodeBuild.

Q: How do these tools handle secrets and sensitive data?
A: Terraform supports sensitive input variables and state encryption via backends. Pulumi encrypts secrets at the field level in state with automatic key management. CDK/CloudFormation supports dynamic references to AWS Secrets Manager and Parameter Store. Pulumi’s field-level encryption is the most granular — individual string values can be marked as secrets regardless of their source.

Q: Can I use these tools for non-cloud infrastructure?
A: Yes. Terraform’s 3000+ providers cover DNS (Cloudflare, Route53), SaaS (Datadog, GitHub, Okta), databases (MySQL, PostgreSQL, MongoDB), and on-premises (VMware, Proxmox, Nutanix). Pulumi covers these through its Terraform bridge plus native providers. CDK is limited to AWS services only.

Related Articles

Leave a Comment