Terraform, Pulumi, and Crossplane

Infrastructure as Code (IaC) has matured into several distinct models, each optimized for different teams, architectures, and operational constraints. Among the most widely used tools today are Terraform, Pulumi, and Crossplane. They overlap in some areas, but in practice they serve different purposes — and successful platform teams often combine them.

This post compares the three from an engineering perspective: how they work, where they fit best, and what patterns emerge when using them together.

Terraform

Terraform is the most established IaC tool and remains the default in many organizations. Its core idea is simple: describe infrastructure declaratively, track state, and apply changes predictably.

Strengths

  • Stable, predictable workflows
    Terraform’s plan/apply model is mature and well understood. State backends, locking, and module versioning are reliable at scale.

  • Largest provider ecosystem
    Hundreds of official and community providers let teams manage everything from cloud primitives to SaaS systems.

  • Clear separation of infrastructure and runtime
    Terraform runs outside Kubernetes, which avoids circular dependencies and makes it suitable for foundational cloud resources.

  • Strong compliance story
    Declarative configs, policies (via Sentinel/Open Policy Agent), and controlled apply paths work well in enterprise environments.

Limitations

  • HCL can get unwieldy
    Complex logic, dynamic resources, or data-driven patterns require workarounds that stretch HCL’s intended use.

  • State management needs discipline
    Teams must manage locks, backends, concurrent applies, and drift manually.

  • Slow feedback loops
    Terraform plans and applies are slower than Kubernetes reconciliation or programmatic IaC.

Best fit

  • Base infrastructure (VPCs, IAM, networks, clusters)
  • Teams that prioritize stability and broad provider support
  • Environments where infra changes must be tightly controlled

Pulumi

Pulumi takes a fundamentally different approach: define infrastructure using general-purpose programming languages such as TypeScript, Go, Python, or C#. This unlocks expressiveness that declarative DSLs struggle with.

Strengths

  • Full programming model
    You get loops, functions, tests, code reuse, conditional logic, typed APIs, and IDE support.

  • Great for complex infrastructure logic
    When resources depend on dynamic inputs, external APIs, or custom workflows, Pulumi’s model shines.

  • Single tool for base + service infrastructure
    Many teams use Pulumi end-to-end when they prefer code-driven workflows.

  • Leverages Terraform’s provider ecosystem
    Pulumi can bridge Terraform providers, reducing ecosystem fragmentation.

Limitations

  • Flexibility requires discipline
    With great power comes the ability to create tangled abstractions quickly.

  • State model still exists
    Similar to Terraform, Pulumi uses a state backend (though typically more hidden).

  • Not Kubernetes-native
    Pulumi drives infra around Kubernetes, not from inside the cluster.

Best fit

  • Teams comfortable with general-purpose languages
  • Full-lifecycle infra management
  • Complex, dynamic resource orchestration
  • Infra tightly integrated with application code

Crossplane

Crossplane extends Kubernetes into an infrastructure control plane. It exposes cloud resources as CRDs and manages them through controllers and continuous reconciliation.

Strengths

  • Kubernetes-native IaC
    Everything is a Kubernetes object with lifecycle managed by controllers. Drift is automatically corrected.

  • Strong fit for platform engineering
    Crossplane’s Composition API lets platform teams build internal abstractions (“Claim a database” → CRD creates network, subnet, DB, backup policy).

  • Self-service without giving developers cloud credentials
    Developers apply CRDs in namespaces; Crossplane provisions resources using platform-managed credentials.

  • Great for service infrastructure
    Databases, queues, buckets, caches — resources tightly linked to applications inside a cluster.

Limitations

  • Not ideal for foundational cloud infrastructure
    It can’t bootstrap the Kubernetes cluster it runs on.

  • Steeper learning curve
    Understanding managed resources, claims, compositions, providers, and reconciliation boundaries takes time.

  • Provider maturity varies
    Much improved in the past years but still not as broad as Terraform’s ecosystem.

Best fit

  • Kubernetes-native organizations
  • Platform teams building internal developer platforms
  • Self-service infrastructure
  • Day-2 drift correction

Architectural Patterns That Work in Practice

In real-world engineering environments, these tools are often complementary.
Below are patterns that show up across platform teams.

Pattern 1 — Terraform for Base Infrastructure + Crossplane for Service Infrastructure

This is the most common layered approach.

Terraform handles:

  • VPCs, subnets, gateways
  • IAM
  • Kubernetes clusters
  • Global networking and org-level resources

Crossplane handles:

  • Databases
  • Queues
  • Buckets
  • Caches
  • Internal abstractions (e.g. CompositePostgresInstance)

Why this works

  • Terraform is stable for foundational infra
  • Crossplane enables day-2 management and self-service
  • Kubernetes owners manage infra without exposing cloud credentials
  • Drift is automatically corrected

This pattern aligns with industry recommendations without forcing a single-tool solution.

Pattern 2 — Pulumi for Everything

Pulumi is appealing when:

  • teams want to define infra in familiar languages
  • infrastructure logic is highly dynamic
  • app and infra code live side by side

Pulumi can comfortably handle both:

  • base infrastructure (networking, clusters)
  • service infrastructure (databases, messaging, storage)

Caveat:
This works best when the team has strong engineering discipline — complex abstractions introduce long-term maintenance overhead.

Pattern 3 — Pulumi + Crossplane for K8s-Native Teams

A common pattern in organizations that operate Kubernetes at scale:

  • Pulumi provisions the foundational cloud environment
    Clusters, networks, security boundaries, org resources.

  • Crossplane manages service infra via API claims
    Developer-facing resources reconciled by Kubernetes.

This provides:

  • strong guardrails
  • continuous reconciliation
  • internal platform APIs
  • full programmability where needed

Key Differences at a Glance

Execution Model

  • Terraform: external engine (plan/apply)
  • Pulumi: external engine using real languages
  • Crossplane: Kubernetes control plane reconciliation

State

  • Terraform/Pulumi: explicit state stored in a backend
  • Crossplane: no external state; desired state is CRDs

Ecosystem support

  • Terraform: broadest
  • Pulumi: broad, plus Terraform bridges
  • Crossplane: improving but more focused

Team fit

  • Terraform: infra/platform teams
  • Pulumi: software-engineering-oriented teams
  • Crossplane: Kubernetes-first and platform-engineering teams

Selecting the Right Tool — Pragmatic Guidance

Choose Terraform when:

  • you need the broadest provider ecosystem
  • stability and clear workflows matter
  • you’re provisioning foundational infrastructure

Choose Pulumi when:

  • your team prefers real languages
  • infrastructure requires dynamic logic
  • you want infra+app in one environment

Choose Crossplane when:

  • you’re building a Kubernetes-native platform
  • you want self-service infrastructure
  • you need continuous drift correction

Use a combination when:

  • you want Terraform’s stability + Crossplane’s Kubernetes-native workflows
  • you want Pulumi’s expressiveness + Crossplane’s platform APIs
  • you want gradual, low-risk adoption across teams

There is no single “best” choice. The right tool depends on your architecture, your platform strategy, and how your teams work.

Summary

Terraform, Pulumi, and Crossplane represent three valid IaC philosophies:

  • Terraform — stable declarative infra with broad provider coverage
  • Pulumi — programmable IaC for dynamic and complex workflows
  • Crossplane — Kubernetes-native control plane for platform engineering and self-service

Used thoughtfully, they complement each other. Many teams use Terraform for foundational infrastructure, Crossplane for managed service provisioning, and Pulumi for dynamic or code-driven workflows.

The goal isn’t choosing a winner — it’s selecting the right tool for each layer of the platform.