Mohammad Gufran Jahangir February 13, 2026 0

You’re not really choosing a tool.

You’re choosing how your team will think about infrastructure for the next 2–5 years:

  • Do you want cloud-native guardrails or multi-cloud freedom?
  • Do you want declarative templates or real programming languages?
  • Do you want a single shared platform workflow or “each app team owns its infra”?

This guide helps you decide fast, without buzzwords, with real examples you can picture in your own org.


Table of Contents

The 15-second answer (for people who just want the pick)

  • Pick Terraform if you need multi-cloud, a huge ecosystem, strong “platform team” workflows, and you want a standard many engineers already know.
  • Pick CloudFormation if you’re all-in on AWS, want deep AWS integration, and prefer a tool that fits AWS governance patterns tightly.
  • Pick Pulumi if you want to define infra using real code (TypeScript/Python/etc.), share libraries like software, and your team is strong in application engineering.

Now let’s make that decision correct for your situation.


1) What are you actually building?

Most teams fall into one (or more) of these realities:

Reality A — “We’re AWS-only and regulated”

You care about:

  • least privilege, approvals, auditability
  • predictable changes
  • strong alignment with AWS services and org controls

Reality B — “We’re multi-cloud or may be later”

You care about:

  • portability across providers
  • one workflow across clouds
  • consistent patterns (networking, IAM, observability)

Reality C — “We ship apps fast; infra should feel like code”

You care about:

  • writing infra logic in code (loops, conditionals, reuse)
  • unit tests, CI patterns, packages
  • platform team providing libraries, app teams consuming them

Keep your “reality” in mind. It will decide most of the answer.


2) The core difference in one table

ToolHow you write infraBest forBiggest strengthCommon pain
TerraformDeclarative HCL + modulesPlatform teams, multi-cloud, standardizationEcosystem + provider coverage + reusable modulesState + module sprawl if not governed
CloudFormationDeclarative YAML/JSON templates (AWS)AWS-native teams, compliance-heavy orgsDeep AWS integration + predictable AWS lifecycleVerbose templates, cross-account/stack complexity
PulumiReal languages (TS/Python/Go/C#)Dev-heavy orgs, internal platforms, reusable infra librariesCode reuse + abstractions + testingEasy to over-engineer; requires code discipline

If that’s enough to choose, stop here and implement well.

If you want the right choice for your team, keep going.


3) The mental model that prevents bad decisions

Terraform’s mental model: “Infrastructure as a graph + state”

You declare desired resources. Terraform builds a dependency graph and uses state to know what exists and what changed.

This is amazing for:

  • consistent rollouts across many environments
  • sharing modules and standards
  • multi-cloud

But it requires discipline around:

  • state storage, locking, access
  • module design and versioning

CloudFormation’s mental model: “AWS stacks manage AWS resources”

You define a template; AWS manages it as a stack. AWS also handles many lifecycle rules (create/update/delete ordering) in an AWS-first way.

Great when:

  • you want AWS-native operations and controls
  • you’re deep in AWS accounts/organizations
  • governance/security teams prefer AWS-managed change flows

But:

  • templates can become huge
  • complex setups often mean many stacks and cross-stack wiring

Pulumi’s mental model: “Infrastructure is software”

You write infra in TypeScript/Python/etc. You can do:

  • loops
  • conditions
  • data structures
  • reuse common libraries

This is powerful when:

  • you have many “similar-but-not-identical” environments
  • app teams want to self-serve using shared components
  • you want real testing patterns

But:

  • without standards, teams create 10 different “styles” of infra quickly
  • “just because you can code it” doesn’t mean you should

4) A real example: “Create an S3 bucket + tags” (3 ways)

The point here isn’t syntax — it’s what your team will live in daily.

Terraform (HCL)

  • Feels like config
  • Great for consistent tagging and patterns via modules
resource "aws_s3_bucket" "logs" {
  bucket = "${var.app}-${var.env}-logs"

  tags = {
    app   = var.app
    env   = var.env
    owner = var.owner
  }
}

CloudFormation (YAML)

  • Very explicit
  • Tightly AWS-shaped
Resources:
  LogsBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "${App}-${Env}-logs"
      Tags:
        - Key: app
          Value: !Ref App
        - Key: env
          Value: !Ref Env
        - Key: owner
          Value: !Ref Owner

Pulumi (TypeScript)

  • Looks like application code
  • Great for shared helper functions
import * as aws from "@pulumi/aws";

const bucket = new aws.s3.Bucket("logs", {
  bucket: `${app}-${env}-logs`,
  tags: { app, env, owner },
});

Now ask: Which style matches your engineers’ brains and daily workflow?


5) The “which team fits which tool” playbook (very practical)

Team type 1: A Platform Team serving many app teams

Your problem: standardization, guardrails, repeatability.

Best fit (usually): Terraform

  • Modules become your “golden paths”
  • Easy to enforce tagging, naming, networking defaults
  • Multi-account + multi-env patterns are common

Pulumi can also fit if your platform team wants to ship reusable “components” as code libraries.
But you must enforce conventions, otherwise you’ll get a zoo.

CloudFormation fits if you’re AWS-only and want AWS-native governance end-to-end.


Team type 2: App teams owning their infra (Dev-heavy org)

Your problem: speed + developer ergonomics + reuse.

Best fit (often): Pulumi

  • App teams love writing infra like code
  • You can ship internal packages like company-network, company-k8s, company-observability
  • Testing patterns are more natural

Terraform can fit if your org is already Terraform-native and you provide high-quality modules.
But developers sometimes find HCL limiting for complex logic.


Team type 3: AWS-only enterprise with strong compliance + governance

Your problem: auditability, controls, predictable processes.

Best fit (often): CloudFormation

  • AWS-native lifecycle and integration patterns
  • Strong match for organizations that want AWS-managed workflows

Terraform can also work well here (many enterprises do it), but your governance model must be solid: state controls, module policies, and review gates.


Team type 4: Multi-cloud org (or “we might be”)

Your problem: consistency across providers, not rewriting everything later.

Best fit: Terraform

  • Provider ecosystem and cross-cloud patterns are a major advantage

Pulumi can also work multi-cloud, but in practice, Terraform is the default pick for multi-cloud standardization across many teams.


6) The decision checklist (answer these 10 questions)

Score each question toward the tool that best matches your answer.

1) Are you AWS-only for the next 3+ years?

  • Yes → CloudFormation or Terraform
  • No / uncertain → Terraform (most common)

2) Does your team prefer real programming languages for infra?

  • Yes → Pulumi
  • No / prefer config → Terraform or CloudFormation

3) Will you build a shared internal platform (golden paths)?

  • Yes → Terraform or Pulumi (platform libraries)
  • No → any, but Pulumi helps developer self-serve

4) Do you need deep AWS-native lifecycle integration?

  • Yes → CloudFormation
  • Not critical → Terraform or Pulumi

5) Do you already have Terraform skills and modules?

  • Yes → Terraform (don’t fight your org)
  • No → evaluate based on team strengths

6) How much complexity is in your infra logic?

Examples: loops across 50 microservices, per-tenant infra, dynamic policies.

  • High logic → Pulumi (code wins)
  • Mostly standard patterns → Terraform/CloudFormation

7) Who will maintain it?

  • Platform engineers → Terraform often scales well with modules
  • Application engineers → Pulumi often feels natural

8) Is “drift detection and correction” critical?

All tools can handle drift, but your process matters more than the tool.

  • If you want “AWS manages the stack story” → CloudFormation
  • If you want “consistent plan/apply pipeline across many providers” → Terraform

9) Do you want the simplest governance story?

  • AWS-only governance → CloudFormation can be simplest
  • Cross-cloud governance → Terraform often simplest
  • Code-centric governance → Pulumi (with strict standards)

10) Are you worried about teams over-engineering abstractions?

  • Yes → Terraform/CloudFormation (more guardrails by nature)
  • No / strong code discipline → Pulumi can be a superpower

7) Common mistakes (and how each tool fails differently)

Terraform mistakes

Mistake: “Modules for everything” until nobody knows what’s inside.
Fix: fewer, higher-quality modules. Version them. Write docs like a product.

Mistake: state becomes scary.
Fix: strong state backend + locking + restricted access + clear recovery runbooks.


CloudFormation mistakes

Mistake: one giant template becomes unmaintainable.
Fix: split by domain (network, compute, data, observability). Keep stacks small.

Mistake: cross-stack references become a spiderweb.
Fix: define stable “outputs contracts” and avoid unnecessary coupling.


Pulumi mistakes

Mistake: infra becomes a full-blown software framework (too clever).
Fix: treat components like a product: stable APIs, minimal surface area, strict reviews.

Mistake: each team writes infra “their way.”
Fix: provide official libraries + linting + examples + templates. Enforce them.


8) A “best-practice” workflow for each (what good looks like)

Terraform workflow that scales

  • One repo (or mono-repo) with:
    • modules/ (platform-owned)
    • envs/ (prod/stage/dev)
  • Pull request plan preview
  • Mandatory code review
  • Drift checks
  • Monthly module updates

Good for: standardization across many teams.


CloudFormation workflow that stays sane

  • Templates split into stacks by domain
  • Change sets reviewed before apply
  • Parameter strategy consistent across environments
  • Clear stack ownership

Good for: AWS-only orgs with strong governance.


Pulumi workflow that stays clean

  • One shared internal package of components:
    • networking, kubernetes, observability, databases
  • App teams consume components, not raw resources
  • Unit tests for components (yes, infra can be tested)
  • Strict coding standards and reviews

Good for: dev-heavy orgs that want reusable infrastructure “SDKs”.


9) The “right” answer for many organizations: use two tools (intentionally)

This is common and often smart:

Pattern 1: Terraform for baseline + Pulumi for app stacks

  • Platform team: Terraform for accounts, networking, clusters, shared services
  • App teams: Pulumi for per-service infra using platform libraries

Pattern 2: Terraform for most + CloudFormation for AWS-only niche

  • Use Terraform broadly
  • Use CloudFormation where AWS-native stacks are already mature internally

The key is not “one tool everywhere.”
The key is “clear boundaries and ownership.”


10) Final recommendation (choose based on your team’s shape)

If you want the simplest, highest-probability decision:

Choose Terraform if:

  • you are (or might become) multi-cloud
  • you need strong standardization across many teams
  • you want a widely adopted, ecosystem-rich approach

Choose CloudFormation if:

  • you are AWS-only
  • compliance/governance is the dominant requirement
  • you want AWS-native lifecycle and stack management

Choose Pulumi if:

  • your engineers think in code and want to reuse libraries
  • you need dynamic infrastructure logic cleanly
  • you’re building a developer platform with reusable components

The last (important) truth

The tool matters, but the operating model matters more:

  • ownership
  • review gates
  • reusable patterns
  • drift detection
  • cost and security guardrails

Pick the tool that matches your team’s natural habits — then enforce a workflow that prevents chaos.

Terraform vs CloudFormation vs Pulumi (AWS + Azure + GCP, dev/stage/prod, Kubernetes): which fits which team?

You’re running the “modern default” stack:

  • All three clouds (AWS, Azure, GCP)
  • Three environments (dev / stage / prod)
  • Kubernetes as the runtime

That combo changes the game.

Because now your biggest problems are not “how do I create a VM?”
Your problems are:

  • Consistency across clouds (networking, IAM, clusters, DNS, logging)
  • Repeatability across environments (same thing, different parameters)
  • Platform guardrails (teams can ship fast without breaking cost/security)
  • Kubernetes add-ons (Ingress, cert-manager, external-dns, secrets, observability)

So let’s pick the right Infrastructure-as-Code approach for this exact reality.


The blunt truth for multi-cloud Kubernetes

If you’re serious about AWS + Azure + GCP long-term, the highest-probability setup is:

✅ Terraform for cloud foundations (multi-cloud baseline)

✅ (Optional) Pulumi for app-team stacks / custom platform components

⚠️ CloudFormation only for AWS-specific “special cases”

Why? Because CloudFormation is AWS-only. In a multi-cloud org, it becomes a second universe you must govern, train, and maintain—with little benefit outside AWS.

Now let’s make this decision fully practical and confident.


1) Your stack split: what belongs where?

Think of your infrastructure in three layers:

Layer A — Cloud foundation (per cloud, per environment)

Examples:

  • Accounts/subscriptions/projects
  • VPC/VNet/VPC Networks + subnets
  • IAM and identities
  • Shared DNS, logging sinks, key management
  • Private networking, peering, routing
  • Container registries
  • Base security policies

✅ Best managed with Terraform (because it spans AWS + Azure + GCP cleanly)


Layer B — Kubernetes platform (per cluster)

Examples:

  • EKS / AKS / GKE clusters
  • Node pools, autoscaling, private cluster settings
  • Ingress controller choices
  • cert-manager, external-dns, CSI drivers
  • service mesh (optional)
  • base observability (Prometheus/Grafana/OTel)

✅ Usually Terraform + Helm (or Terraform + GitOps)
✅ Or Pulumi if your platform team builds reusable “components”


Layer C — Application delivery on Kubernetes

Examples:

  • namespaces, RBAC, quotas
  • app Helm releases
  • config per environment
  • secrets integration
  • service-to-service policies

✅ Best handled by GitOps (Argo CD / Flux) regardless of the IaC tool
(But Pulumi can be used too if your teams prefer code-driven deployments.)


2) The “fits which team” map (for your exact setup)

Team type 1: Central Platform Team (multi-cloud + K8s)

Your job: create a paved road so app teams don’t reinvent infra 50 times.

Best fit: Terraform-first

Because you can standardize:

  • network layout per env across clouds
  • naming/tagging/labels
  • IAM policies and guardrails
  • cluster baseline and addons

Terraform excels when platform teams provide “golden modules” and everyone consumes them.

Where Pulumi helps:
If your platform team wants to ship internal reusable components that feel like SDKs:

  • CompanyEksCluster()
  • CompanyAksCluster()
  • CompanyGkeCluster()
  • CompanyObservabilityStack()

Pulumi is fantastic here—if you have strong code governance.


Team type 2: App Teams (deploying services to K8s)

Your job: ship features reliably.

Best fit: GitOps + Helm/Kustomize (tool-agnostic)

App teams should rarely need to write “cloud IaC”.
They should:

  • get namespaces, quotas, and baseline policies from platform
  • deploy apps via GitOps
  • request platform changes via PRs/tickets

Where Pulumi fits:
If app teams also need per-service cloud resources:

  • managed databases
  • pub/sub topics
  • object buckets
  • managed caches

Pulumi can feel more natural for dev teams because it’s code-first.
But Terraform modules can also work well if they’re easy to consume.


Team type 3: Security / Compliance / Governance

Your job: prevent expensive and risky mistakes at scale.

Best fit: Terraform with strict controls + policy-as-code

Why:

  • one standard pipeline to enforce
  • one tagging standard across clouds
  • easier audit and drift management with one approach

Where CloudFormation fits:
Only if you must use AWS-native stack workflows for certain regulated services or legacy stacks.


3) The best-practice architecture for AWS+Azure+GCP (dev/stage/prod)

Here’s the setup that keeps your life sane.

Recommended: “Terraform foundation + GitOps apps” model

Repo 1: platform-foundation (Terraform)

Structure example:

  • modules/
    • aws-network/
    • azure-network/
    • gcp-network/
    • eks-cluster/
    • aks-cluster/
    • gke-cluster/
    • observability-baseline/
  • envs/
    • dev/
    • stage/
    • prod/

Each env calls the same modules with different parameters.

What this gives you:

  • one standardized architecture
  • easy replication across envs
  • consistent guardrails

Repo 2: apps-gitops (Argo CD / Flux)

Structure example:

  • clusters/dev/
  • clusters/stage/
  • clusters/prod/
  • apps/
    • payments/
    • search/
    • notifications/

Each app has Helm/Kustomize overlays per environment.

What this gives you:

  • consistent deployment flows
  • audit trails for changes
  • rollbacks and progressive delivery patterns

4) Real multi-cloud example: “same app needs a bucket + DNS + secrets”

Imagine one service: image-processor

It needs:

  • storage bucket
  • DNS name
  • secrets
  • Kubernetes deployment

In Terraform-first approach

  • Terraform creates cloud resources:
    • S3 / Blob / GCS bucket (depending on cloud)
    • DNS records (cloud DNS zone)
    • secrets manager or key vault references
  • GitOps deploys the app:
    • Helm chart values per environment
    • External Secrets / CSI driver configuration
    • Ingress rules

Why this works well:
Cloud resources are stable and controlled. App deployments are fast and frequent.


In Pulumi-heavy approach

Pulumi code provisions:

  • the bucket + DNS + secret references
  • AND deploys the Helm release

Why teams like it:
One language. One pipeline. Everything is code.

Why it can hurt:
App deployments become tied to infra provisioning workflows, and you may introduce slower, riskier deployments if not separated carefully.


5) Where CloudFormation still makes sense (even in multi-cloud)

Even if you’re multi-cloud, CloudFormation can be useful in three narrow cases:

  1. Legacy AWS stacks you don’t want to rewrite
  2. AWS-only features where your org wants AWS-native stack governance
  3. Account bootstrap in AWS if your company already built strong patterns there

But for your default path, CloudFormation becomes “extra mental overhead.”


6) The decision framework: pick your “default tool” + allowed exceptions

For your setup, the smartest rule is:

Default tool for foundations: Terraform

  • AWS + Azure + GCP all supported
  • repeatable dev/stage/prod patterns
  • common module system for platform team
  • consistent governance and reviews

Allowed exception: Pulumi for internal platform libraries

Use Pulumi if:

  • you have strong app engineering culture
  • you want reusable “components” with tests
  • you can enforce standards across teams

Rare exception: CloudFormation for AWS-only areas

Use it only where it adds real value and doesn’t create parallel universes.


7) What to choose: the final recommendation for your stack

✅ Best overall: Terraform + GitOps

Use Terraform to build and manage:

  • networks
  • IAM
  • clusters (EKS/AKS/GKE)
  • cluster baseline add-ons (or cluster bootstrap)

Use GitOps to manage:

  • Kubernetes workloads
  • Helm/Kustomize overlays (dev/stage/prod)
  • app configs, rollouts, rollbacks

✅ Optional upgrade: add Pulumi where code brings leverage

Add Pulumi if you want:

  • reusable internal platform SDKs
  • better abstraction for complex “per-tenant/per-app” infra logic
  • dev-friendly patterns with testing

⚠️ Limit CloudFormation

Keep CloudFormation:

  • only for AWS-special cases
  • do not make it the main standard in a multi-cloud org

8) A simple “who uses what” chart (copy for your org doc)

  • Platform Team
    • Terraform (cloud foundation + clusters)
    • GitOps bootstrap (Argo/Flux install and baseline)
    • Optional Pulumi (platform component libraries)
  • App Teams
    • GitOps (apps on K8s)
    • Terraform modules OR Pulumi components (only when app needs cloud resources)
  • Security/Governance
    • Policies, tagging, approvals around Terraform plans
    • Rules for what app teams can/can’t provision directly

The “line-by-line curiosity” takeaway

If you’re multi-cloud + Kubernetes, your biggest win is not arguing tools forever.

Your biggest win is:

Standardize foundations once, then let apps ship fast on Kubernetes.

Terraform is the safest foundation standard.
GitOps is the safest app delivery standard.
Pulumi is the power tool when “infra needs code,” but only with strong governance.



Category: 
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments