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. They offer 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.