How does Terraform compare to Pulumi and native IaC tools like CloudFormation/ARM templates?
Quick Answer
CloudFormation (AWS) and ARM/Bicep (Azure) are **native, single-cloud** IaC tools maintained by the cloud provider itself — deep, immediate support for that cloud's newest features, but no multi-cloud story and typically YAML/JSON-based (Bicep and CDK aside). **Pulumi** takes a different approach from Terraform's: instead of HCL, you write actual general-purpose code (TypeScript, Python, Go, C#), giving you real loops, functions, and your language's own tooling/testing ecosystem, while still being multi-cloud and provider-plugin-based similarly to Terraform. Terraform sits in between: multi-cloud like Pulumi, but using a purpose-built declarative language (HCL) rather than a general-purpose one, with the largest, most mature ecosystem of community providers and modules. The practical choice often comes down to team preference (a dedicated IaC language vs. code in a language you already know) and whether multi-cloud portability matters versus staying deeply integrated with a single provider's native tooling.
Detailed Answer
This is a common "compare the landscape" interview question — the goal is showing you understand the actual axes of difference (single-cloud vs. multi-cloud, purpose-built language vs. general-purpose code), not just that alternatives exist.
CloudFormation (AWS) and ARM/Bicep (Azure) — native, single-cloud
# CloudFormation snippet
Resources:
WebInstance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-0abcdef1234567890
InstanceType: t3.micro
Maintained directly by the cloud provider, so brand-new service features are typically supported here first (sometimes before any third-party Terraform provider catches up). The tradeoff is that it only manages that one cloud — a CloudFormation stack has no way to also provision an Azure resource, and vice versa for ARM/Bicep. Traditionally YAML/JSON-based, though newer tools (AWS CDK, Bicep) layer more ergonomic syntax or real code generation on top.
Pulumi — multi-cloud, general-purpose code
// Pulumi snippet (TypeScript)
const web = new aws.ec2.Instance("web", {
ami: "ami-0abcdef1234567890",
instanceType: "t3.micro",
});
Pulumi is architecturally closer to Terraform than to CloudFormation: it's multi-cloud, provider-plugin-based, and maintains its own state. The key difference is the language — instead of HCL, you write real TypeScript/Python/Go/C#, meaning genuine loops, conditionals, functions, and access to your language's existing package ecosystem, testing frameworks, and IDE tooling, rather than HCL's more constrained (though still quite capable) expression language.
Terraform — multi-cloud, purpose-built language
resource "aws_instance" "web" {
ami = "ami-0abcdef1234567890"
instance_type = "t3.micro"
}
Terraform sits between the two: multi-cloud like Pulumi (via its provider ecosystem — the largest and most mature of any multi-cloud IaC tool), but expressed in HCL, a language designed specifically for describing infrastructure rather than a general-purpose one. This means a gentler learning curve for infrastructure-focused engineers who aren't necessarily software developers, at the cost of HCL's expression language being intentionally more limited than a real programming language (no custom functions, as covered earlier, being one concrete example).
How teams actually decide
- Deeply single-cloud, want the provider's newest features immediately → CloudFormation/ARM.
- Team is full of software engineers who'd rather write real code (with real tests, real abstractions) than learn a new DSL, and values multi-cloud → Pulumi.
- Want multi-cloud with the largest module/provider ecosystem and a language purpose-built for the domain, without requiring every contributor to be a software engineer → Terraform.
None of these is universally "correct" — the decision usually comes down to the makeup of the team and how much the org's infrastructure genuinely spans multiple clouds versus living entirely in one.