Terraform vs Pulumi vs CloudFormation: A Pragmatic 2025 Comparison
Three tools that look similar and feel completely different once your team has 500 resources. Here is the comparison that matters at scale.
Four axes that matter
Most comparisons focus on syntax. Syntax is the smallest thing.
- Language surface: how expressive, how typed, how testable.
- State model: how the tool knows what's deployed, and what happens when that knowledge is wrong.
- Blast radius: how big a mistake can get before you can stop it.
- Ecosystem: providers, modules, policy engines, test tooling.
Terraform
HCL is purpose-built for infra, which means it's great for describing resources and awkward for anything that needs real logic. Typed modules are a recent addition; most teams still manage module interfaces via convention.
State lives in a remote backend (S3 + DynamoDB is the default). Locking prevents concurrent applies; state drift is a persistent operational concern. Mature ecosystem: every cloud, every SaaS, every policy engine (OPA, Sentinel).
Pulumi
Uses real programming languages (TypeScript, Python, Go, .NET) with the cloud provider SDKs as the resource definitions. This means anything you'd do in code, loops, conditionals, unit tests, works directly, no template hacks.
State is managed by the Pulumi service by default (or self-hosted). Blast radius is tighter than Terraform because preview diffs are typed and IDE-assisted. Smaller ecosystem than Terraform, but the Terraform bridge means most TF providers work from Pulumi.
CloudFormation
AWS-native. YAML/JSON templates, state managed entirely by the AWS CloudFormation service. No state file to lose or corrupt.
The big win is integration: IAM, service quotas, drift detection, nested stacks all work without extra tooling. The big loss is vendor lock (not cross-cloud), and templates become hard to read past a few hundred resources. CDK + SAM mitigate some of this by generating CFN from code.
How to pick at your scale
- Single cloud, small team, AWS-only: CDK (CloudFormation under the hood). Fastest path, tight integration, no state headaches.
- Multi-cloud or SaaS-heavy: Terraform. The ecosystem is still unmatched.
- Heavy logic, strong typing, testable infra code: Pulumi. The language surface pays for itself within a year.
The worst outcome is migrating between them mid-growth. Pick once, commit for 2,3 years, revisit at the next major architectural shift.
The worst outcome is migrating between them mid-growth. Pick once. Revisit at the next major architectural shift.
Red flags when onboarding a new team
They bikeshed over syntax without asking about state, blast radius, or policy. That is a team that will pick the wrong tool confidently.
They pattern-match on what their last company used. The last company was probably a different size, cloud, and stage. Evaluate for the next three years, not the last three.
They skip the 'what happens when the state file is wrong' conversation. Every IaC horror story starts with stale state.