Terraform vs Pulumi vs CloudFormation: Choosing an IaC Tool
Terraform vs Pulumi vs CloudFormation: Choosing an IaC Tool
Terraform, Pulumi, and CloudFormation all manage infrastructure as code, but they differ in three decisive ways: the language you write in, how state is managed, and how deeply they integrate with their cloud. This guide compares them on those dimensions and gives you a decision framework.
The Three Approaches
Terraform: declarative HCL (HashiCorp Configuration Language), state stored in backends, multi-cloud via providers.
Pulumi: infrastructure in real programming languages (TypeScript, Python, Go), state in the Pulumi service or self-hosted.
CloudFormation: AWS-native, YAML/JSON templates, state managed by AWS itself.
Language: The First Decision
# Terraform — HCL, declarative
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
tags = {
Name = "web-server"
}
}
// Pulumi — TypeScript, imperative with declarative resources
import * as aws from "@pulumi/aws";
const web = new aws.ec2.Instance("web", {
ami: "ami-0c55b159cbfafe1f0",
instanceType: "t3.micro",
tags: { Name: "web-server" },
});
export const publicIp = web.publicIp;
# CloudFormation — YAML, declarative
Resources:
WebInstance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-0c55b159cbfafe1f0
InstanceType: t3.micro
Tags:
- Key: Name
Value: web-server
The language choice is not cosmetic. Pulumi's real-language model enables loops, conditionals, and functions without HCL's awkward expressions:
// Pulumi: real loops and conditionals
const instances = environments.map(
(env) =>
new aws.ec2.Instance(`web-${env}`, {
instanceType: env === "prod" ? "m5.large" : "t3.micro",
tags: { Environment: env },
}),
);
Terraform can do this with for_each and count, but the syntax is harder to read and test. CloudFormation has no loops at all — you generate templates or repeat blocks.
State Management
State is the source of truth for what exists in your cloud.
Terraform: state is a JSON file in a backend (S3, Terraform Cloud, local). You must configure locking and remote storage yourself. State corruption or drift is a real operational concern.
# backend.tf — remote state with locking
terraform {
backend "s3" {
bucket = "my-tf-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "tf-locks"
}
}
Pulumi: state in the Pulumi Cloud service (or self-hosted), with built-in locking, history, and policy. Less to configure, but a dependency on the service.
CloudFormation: AWS manages state entirely. No state files, no locking, no drift files. This is CloudFormation's biggest operational advantage: the state problem is solved for you.
Multi-Cloud
| Tool | Multi-Cloud | Provider Model |
|---|---|---|
| Terraform | Excellent | 1000+ providers, community |
| Pulumi | Excellent | Native providers per cloud |
| CloudFormation | AWS only | N/A |
If you run AWS + GCP + Azure, Terraform or Pulumi are the only real options. CloudFormation locks you to AWS.
Drift and Diffing
All three detect drift between declared and actual state, but the experience differs:
- Terraform:
terraform planshows a precise diff. Drift detection requiresterraform refreshor plan runs. - Pulumi:
pulumi previewshows a diff with the same precision, plus the ability to write tests against the plan. - CloudFormation: drift detection is a separate feature you must enable per stack; diffs are less granular.
Testing Infrastructure Code
This is where Pulumi's language model shines:
// Pulumi: unit-test your infrastructure like application code
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
pulumi.runtime.setMocks({
newResource: (args) => ({ id: `${args.name}_id`, state: args.inputs }),
call: (args) => args.inputs,
});
it("tags all instances with the environment", async () => {
const infra = await import("./infra");
const instance = await infra.web.instance;
expect(instance.tags.Environment).toBe("prod");
});
Terraform has terraform test and third-party tools (Terratest), but testing HCL is inherently harder than testing TypeScript.
Comparison Table
| Aspect | Terraform | Pulumi | CloudFormation |
|---|---|---|---|
| Language | HCL | TS/Python/Go/etc | YAML/JSON |
| State | Backend (you manage) | Pulumi service | AWS-managed |
| Multi-cloud | Yes | Yes | No |
| Loops/conditionals | Awkward | Native | None |
| Testing | Limited | Strong | Limited |
| Ecosystem | Largest | Growing | AWS-native |
| Learning curve | Moderate | Moderate | Low (AWS teams) |
Decision Guide
| Your situation | Choose |
|---|---|
| Multi-cloud, largest ecosystem | Terraform |
| Infrastructure as real code, testing | Pulumi |
| AWS-only, want zero state management | CloudFormation |
| Team already knows HCL | Terraform |
| Team is TypeScript/Python-first | Pulumi |
| AWS CDK alternative (real language, AWS) | CDK (not listed) |
Implementation Checklist
- Decide the language: HCL, real code, or YAML
- Check multi-cloud requirements first
- Evaluate state management: who owns the state problem?
- Prototype loops and conditionals you actually need
- Test the diff/plan experience on your team
- Consider testing requirements for infrastructure
- Plan the migration path from any existing tooling
MatterAI builds frontier AI infrastructure for engineering teams — from inference-optimized models to autonomous coding agents and agentic code reviews.
Explore what we're building:
- Orbital IDE — Autonomous AI coding agent with background agents and deep codebase memory
- AI Code Reviews — Agentic pre-commit reviews across GitHub, GitLab, and Bitbucket
- Axon Models — Frontier-grade reasoning models at 70% lower inference cost
Share this Guide:
More Guides
Local LLMs in Your IDE: Connecting Ollama to Coding Agents and Autocomplete
Wire local models into VS Code, JetBrains, Cline, Continue, and Aider via the OpenAI-compatible API. Covers model routing, context budgets, tool calling with small models, and when a local model is the right choice for the job.
15 min readBuilding a Self-Hosted AI Stack: Ollama, Open WebUI, and Local RAG
Stand up a fully self-hosted AI stack on a single machine: Ollama for inference, Open WebUI as the chat interface, local embeddings for RAG, and a reverse proxy for secure access. No cloud dependency, no data leaving your network.
17 min readTop 5 Open-Source Coding Models to Run on Your Mac (2026)
The best local coding models for Apple Silicon in 2026, ranked by quality per gigabyte of unified memory. Covers qwen3-coder, devstral, gpt-oss, and more with real pull tags, sizes, and context windows.
14 min readRunning LLMs Locally: GGUF, Quantization, and Memory Planning
Learn the GGUF format, the quantization ladder from Q2 to FP16, and the exact memory math for running models on Apple Silicon and NVIDIA GPUs. Includes Ollama and llama.cpp tuning for KV cache and context.
15 min readOllama vs vLLM vs llama.cpp: Choosing the Right Local LLM Runtime
Compare the three dominant local LLM runtimes on architecture, throughput, hardware, and deployment context. Includes benchmark data, a decision framework, and a migration path from Ollama to vLLM.
16 min readContinue Reading
Local LLMs in Your IDE: Connecting Ollama to Coding Agents and Autocomplete
Wire local models into VS Code, JetBrains, Cline, Continue, and Aider via the OpenAI-compatible API. Covers model routing, context budgets, tool calling with small models, and when a local model is the right choice for the job.
15 min readBuilding a Self-Hosted AI Stack: Ollama, Open WebUI, and Local RAG
Stand up a fully self-hosted AI stack on a single machine: Ollama for inference, Open WebUI as the chat interface, local embeddings for RAG, and a reverse proxy for secure access. No cloud dependency, no data leaving your network.
17 min readTop 5 Open-Source Coding Models to Run on Your Mac (2026)
The best local coding models for Apple Silicon in 2026, ranked by quality per gigabyte of unified memory. Covers qwen3-coder, devstral, gpt-oss, and more with real pull tags, sizes, and context windows.
14 min readShip Faster. Ship Safer.
Join thousands of engineering teams using MatterAI to autonomously build, review, and deploy code with enterprise-grade precision.
