Skip to content

Comparison: Infrastructure as Code Tools

Category: Infrastructure as Code Last meaningful update consideration: 2026-03 Verdict (opinionated): Terraform (or OpenTofu) for multi-cloud. CDK for AWS-only shops that want real programming languages. Pulumi for teams that hate HCL but want Terraform-level provider support. Crossplane for K8s-native infrastructure management.

Quick Decision Matrix

Factor Terraform / OpenTofu Pulumi CloudFormation CDK Crossplane
Learning curve Medium (HCL) Low-Medium (your language) Medium (JSON/YAML) Medium (your language) High (K8s + XRDs)
Operational overhead Low Low None (AWS-managed) None (AWS-managed) Medium (K8s operator)
Cost at small scale Free Free (OSS) Free Free Free
Cost at large scale Free (OSS) / HCP paid Pulumi Cloud paid Free Free Free
Community/ecosystem Massive (providers) Growing AWS-only AWS-only (mostly) Growing (CNCF)
Hiring Easy Moderate Easy (AWS) Growing Niche
Multi-cloud Excellent Excellent No Mostly no Yes (providers)
State management S3/GCS/remote backends Pulumi Cloud / self-managed AWS-managed AWS-managed K8s etcd
Language HCL Python, TS, Go, C#, Java JSON/YAML Python, TS, Go, C#, Java YAML (K8s CRDs)
Drift detection terraform plan pulumi preview Drift detection Via CloudFormation Continuous reconciliation
Testing Terratest, plan analysis Unit tests in your language TaskCat, cfn-lint CDK Assertions K8s tooling
Provider coverage 3000+ providers 150+ providers + TF bridge AWS only AWS only (mostly) 50+ providers

When to Pick Each

Pick Terraform / OpenTofu when:

  • You need to manage infrastructure across multiple cloud providers
  • Your team is comfortable with a domain-specific language (HCL) purpose-built for IaC
  • Provider coverage matters — every cloud service has a Terraform provider
  • You want the largest community, most examples, and most modules available
  • Reproducible planapply workflow is your standard operating procedure
  • OpenTofu if the BSL license concerns you; Terraform if you want HashiCorp ecosystem integration

Pick Pulumi when:

  • Your team strongly prefers using a general-purpose programming language (TypeScript, Python, Go)
  • You want real programming constructs: loops, conditionals, functions, classes, unit tests
  • The Terraform Bridge gives you access to most Terraform providers without writing HCL
  • You want component resources (reusable infrastructure abstractions) in your language
  • You dislike HCL and value developer experience over ecosystem breadth

Pick CloudFormation when:

  • You are 100% AWS and want a fully managed IaC service with no state files to manage
  • You need native integration with AWS features like StackSets (multi-account), Change Sets, and Service Catalog
  • Your organization is conservative and prefers an AWS-supported tool
  • Compliance requirements favor AWS-native tools

Pick CDK when:

  • You want CloudFormation's reliability with real programming languages
  • Your team writes TypeScript, Python, or Go and wants infrastructure defined alongside application code
  • You want L2/L3 constructs that provide sensible defaults (e.g., new Vpc() with best-practice subnets)
  • You are building AWS-centric and CloudFormation is the backing engine you trust

Pick Crossplane when:

  • You want infrastructure management as a Kubernetes-native experience
  • Platform teams building self-service infrastructure APIs for product teams
  • Continuous reconciliation (like GitOps but for cloud resources) is important
  • You want to compose custom platform APIs (Composite Resources) on top of cloud providers
  • You are already operating Kubernetes and want to extend its control plane to cloud resources

Nobody Tells You

Terraform / OpenTofu

  • State file management is the #1 source of Terraform pain. State locking, state corruption, state drift, and "someone ran apply locally" are constant battles. Use remote backends (S3 + DynamoDB) from day one.
  • The BSL license change fractured the community. OpenTofu exists as a fork but provider ecosystem parity is not guaranteed long-term. Choose deliberately.
  • terraform plan output is not a reliable diff for complex changes. Resource recreation, count/for_each changes, and provider-side defaults create surprises.
  • Module versioning and the Terraform Registry are convenient but create supply chain risk. Vendoring modules or writing your own is safer for production.
  • Large state files (1000+ resources) make plan and apply slow. State splitting across workspaces or Terragrunt configurations adds management overhead.
  • terraform import is painful. It brings the resource into state but does not generate the HCL. You write the code manually and iterate until plan shows no diff.
  • The moved block helps with refactoring but does not cover all cases. Renaming a module still risks resource recreation.

Pulumi

  • "Use your favorite language" is the pitch, but it means your IaC is as complex as your team makes it. Overengineered abstractions in Python/TypeScript are harder to debug than flat HCL.
  • Pulumi's state management defaults to Pulumi Cloud (their SaaS). Self-managed backends (S3, Azure Blob) work but lack the UI and collaboration features.
  • The Terraform Bridge is clever — it wraps Terraform providers for Pulumi — but bridged providers sometimes lag behind Terraform provider releases.
  • Pulumi's community is smaller. When you hit an edge case, there are fewer Stack Overflow answers and blog posts.
  • Pulumi Automation API (embedding Pulumi in your application) is powerful for platform engineering but is a complexity multiplier.
  • Testing IaC with real programming language test frameworks (pytest, Jest) is Pulumi's superpower but requires discipline — most teams do not write IaC tests.

CloudFormation

  • CloudFormation error messages are infamously unhelpful. "UPDATE_ROLLBACK_FAILED" tells you nothing about what went wrong.
  • Stack updates that fail can leave you in a stuck state that requires manual intervention or stack deletion.
  • CloudFormation resource coverage lags behind the AWS API. New services and features often take months to appear.
  • Nested stacks add dependency management headaches. Cross-stack references via Exports create coupling that resists refactoring.
  • The 500-resource limit per stack forces you into nested stacks or stack splitting for large environments.
  • YAML/JSON templates are verbose and repetitive. CloudFormation intrinsic functions (!Ref, !GetAtt, !Sub) are not a real programming language.

CDK

  • CDK generates CloudFormation templates under the hood. When things break, you debug CloudFormation, not CDK. Understanding both layers is required.
  • CDK synth output is massive, auto-generated CloudFormation. Reviewing it in PRs is impractical, which means you lose the "infrastructure change review" benefit.
  • L2/L3 constructs are opinionated. When the defaults do not match your requirements, you drop to L1 (raw CloudFormation) and lose the abstraction benefit.
  • CDK version upgrades break things. Construct library versions must be compatible with the CDK core, and peer dependency issues are common.
  • The CDK Bootstrap stack must be deployed per account per region before CDK works. This is a manual step that surprises new teams.

Crossplane

  • Crossplane is complex. You are running a K8s operator that manages cloud resources via CRDs. Debugging "why did my RDS instance not create" requires understanding K8s controllers, Crossplane providers, and cloud APIs.
  • Provider readiness varies wildly. The AWS provider covers most services, but GCP and Azure providers have gaps.
  • Composition (building custom APIs) is powerful but the authoring experience is YAML-heavy and hard to test.
  • Crossplane turns your K8s cluster into a control plane for cloud resources. If your cluster goes down, cloud resource reconciliation stops. This is a different risk model than Terraform.
  • Resource creation is slower than Terraform — the reconciliation loop adds latency.

Migration Pain Assessment

From → To Effort Risk Timeline
CloudFormation → Terraform Medium-High Medium 2-4 months
Terraform → Pulumi Medium Low 1-3 months (tf2pulumi tool helps)
Pulumi → Terraform Medium Low 1-3 months
CloudFormation → CDK Medium Low 1-2 months
Terraform → Crossplane High High 3-6 months
Manual (console) → Terraform High Medium 2-6 months

The scariest migration is from manual (console/CLI) to any IaC tool. It requires importing existing resources, which means writing code for infrastructure you did not provision through code. Budget for a thorough resource inventory first.

The Interview Answer

"Terraform is my default for multi-cloud because the provider ecosystem is unmatched and HCL strikes a good balance between readability and expressiveness. For AWS-only organizations, CDK lets you use real programming languages with CloudFormation reliability. The deeper insight is that the tool matters less than the practice: whatever you choose, the value comes from peer-reviewed infrastructure changes, automated plan-and-apply pipelines, and state management discipline. Teams that 'terraform apply' from laptops get the same chaos as teams with no IaC at all."

Cross-References