Skip to main content

Crossplane vs Cluster API: Two CNCF Answers to "Should Infrastructure Be an API?" — and Where a Self-Hosted PaaS Draws the Line

11 min readDora NodaDora Noda
Share
On this page

Two CNCF projects looked at the same question — should infrastructure be an API? — and gave answers so different they barely seem to be about the same stack. Crossplane, which graduated from the CNCF in November 2025, says yes to everything: compute, storage, databases, applications, and as of June 2026 even distributed GPU inference fleets, all modeled as Kubernetes-style declarative resources behind one control plane. Cluster API, a Kubernetes SIG subproject, says yes to exactly one thing — the lifecycle of Kubernetes clusters themselves — and maintains a written list of everything it refuses to do beyond that.

A March 2026 CNCF ambassador post, "Crossplane and AI: The case for API-first infrastructure," sharpened the stakes: in a world where AI agents write and ship code, "the bottleneck is everything that happens after git push," and agents need "a unified, structured, machine-readable interface" to infrastructure or their autonomy stalls. Both projects agree on that premise. They disagree — productively — on how much of the world one API should swallow. Here is the side-by-side, up front:

CrossplaneCluster API
Design goalYour entire platform — infra and apps — as a single custom APIDeclarative provisioning, upgrading, and operation of Kubernetes clusters
API surfaceComposite Resource Definitions (XRDs), Compositions, managed resources — namespaced by default since v2.0Cluster, Machine, MachineSet, MachineDeployment, control plane and bootstrap resources
ScopeAnything with an API: cloud services, databases, apps, GPU fleets (Modelplane)Only what it takes to make a conformant Kubernetes cluster exist, scale, upgrade, and die
Explicitly refuses toVery little — v2 removed the claim model and opened composition to any Kubernetes resourceManage infrastructure unrelated to running Kubernetes; span one cluster across providers; duplicate kubelet/apiserver config tooling
Multi-cloud stanceCore value proposition: one abstraction over many providersPer-provider implementations (AWS, Hetzner, vSphere, Docker…); no abstraction layer above them
StatusCNCF graduated (Nov 6, 2025); 7 years, 3,000+ contributors, 100+ releasesKubernetes SIG Cluster Lifecycle subproject; the de facto standard for declarative cluster lifecycle
AI-agent storyThe pitch itself: one machine-readable API so agents stop being "fragile orchestrators"Implicit: cluster state as typed resources any controller — or agent — can reconcile against

For a platform team choosing what to build on, the honest answer is not "pick the winner." It is that these are complementary layers — and knowing exactly where each one's ambition stops tells you where to draw your own line. That is the argument this post makes, ending with where bex — a self-hosted, open-source PaaS whose stated non-goal is multi-cloud abstraction — draws its.

What Crossplane Is Actually Optimizing For

Crossplane's bet is breadth. Its v2.0 release in August 2025 — arriving after what the project described as "seven years, 3,000+ contributors, and over 100 releases" — was a deliberate widening of scope. Composite resources became namespaced by default, aligning with Kubernetes multi-tenancy conventions. The v1 claim model (the indirection where developers created a "claim" that referenced a cluster-scoped composite resource) was removed entirely. And most tellingly, compositions can now include any Kubernetes resource — Deployments, Services, monitoring rules — not just cloud infrastructure. The announcement's framing was explicit: applications are now first-class citizens, so a platform team can hand developers one custom resource that provisions a database, deploys the app, and wires up networking in a single declarative object.

One clarification worth making, because a lot of 2026 commentary still uses v1 language: Crossplane's pitch is often summarized as a "claim-based API," but claims are gone. The current model is simpler — you define an XRD, write a Composition, and consumers create namespaced composite resources directly. The design point survives the terminology change: platform teams define the API; everyone else, human or agent, consumes it.

Version 2.0 also added declarative day-two operations — a new Operation type with scheduled (CronOperation) and event-driven (WatchOperation) variants for backups, upgrades, and maintenance — and v2.2 followed in March 2026 with reliability and observability work. The trajectory is consistent: everything a platform does, expressed as one Kubernetes-style API.

The AI argument layers on top of this. The February and March 2026 posts from the Crossplane community and CNCF argue that fragmented platforms force AI agents to become "fragile orchestrators" gluing together dashboards, CLIs, and ticket queues — and that a single declarative API with desired state, observed status, and policy enforced at execution is what makes agent autonomy safe rather than terrifying. Whatever you think of Crossplane's scope, that diagnosis is hard to argue with.

Modelplane: The Maximal Expression of "Everything Is an API"

If you want to see how far the Crossplane design point stretches, look at Modelplane, announced by Crossplane co-founder Nic Cope in June 2026. It is an open-source control plane for distributed GPU inference — placing large-model serving workloads across a fleet of accelerators spanning multiple clusters and providers. The striking part is the implementation: it is, in Cope's words, "top to bottom, a Crossplane configuration. It has no bespoke controllers and no custom operators: it's compositions and composition functions."

The resource model reads like a textbook case of infrastructure-as-API:

  • InferenceCluster — a fleet-scoped declaration of GPU capacity: node pools, accelerator types, counts
  • ModelDeployment — a namespaced resource where an ML team declares the model to serve, the engine, and replica count
  • ModelReplica — an individual placed model instance
  • InferenceClass — hardware capability declarations following Kubernetes Dynamic Resource Allocation (DRA)

Scheduling happens in two layers. A fleet-level composition function — written in Python, executing as a pure function of observed state — evaluates every ModelDeployment against every InferenceCluster's declared capacity and decides placement, using CEL predicates (the same expression language DRA uses) for resource matching. Then each individual cluster's ordinary Kubernetes scheduler and DRA bind pods to specific GPUs. The TODO-list framing of "even AI model endpoints as composite resources" is not an exaggeration; it shipped.

But notice what Modelplane quietly assumes: the clusters already exist. An InferenceCluster resource declares capacity — it does not create machines, install control planes, or roll upgrades across nodes. The most ambitious everything-as-API system in the Crossplane ecosystem still stands on a substrate someone else has to provide. Which brings us to the project optimizing for exactly that substrate.

What Cluster API Is Actually Optimizing For

Cluster API's bet is depth. Its charter is one sentence: declarative APIs and tooling to simplify provisioning, upgrading, and operating multiple Kubernetes clusters. Its resource model mirrors the Deployment/ReplicaSet/Pod hierarchy that Kubernetes application operators already know, but for machines: a MachineDeployment manages MachineSets, which manage Machines, which an infrastructure provider (AWS, Azure, vSphere, Hetzner, plain Docker for testing) realizes as actual servers, while bootstrap providers (kubeadm by default) turn those servers into cluster nodes and dedicated control-plane resources manage the cluster's brain.

What makes Cluster API unusual among infrastructure projects is its written non-goals. The project explicitly declines to:

  • Manage infrastructure unrelated to running Kubernetes clusters
  • Support a single cluster spanning multiple infrastructure providers
  • Manage clusters it didn't provision
  • Duplicate configuration tooling that belongs to kubelet or the API server
  • Absorb every existing lifecycle tool (kOps, Kubespray, managed services) into its model

This narrowness is a design decision, not a missing roadmap. Because the scope is small, the machine-lifecycle machinery inside it is deep: rolling upgrades of worker pools via MachineDeployment strategies, MachineHealthChecks that automatically remediate failed nodes, declarative control-plane scaling, and an ecosystem of providers that each solve one infrastructure target well. Cluster API turns the cluster itself into a Kubernetes-style API — and then, deliberately, stops.

Same Question, Opposite Ends of the Stack

Put the two side by side and the "versus" framing dissolves into a stack diagram:

  • Bottom: machines and clusters. Cluster API's territory. The API objects are Machines and control planes; the reconciliation loops handle OS images, bootstrap, upgrades, and node health.
  • Middle: a running, conformant Kubernetes cluster — the interface both projects agree on.
  • Top (optional): everything above the cluster as a custom API. Crossplane's territory: databases, cloud services, application platforms, and at the far end, Modelplane's GPU fleet placement.

Crossplane assumes a cluster exists and makes everything above it declarative. Cluster API makes the cluster's own existence declarative and leaves everything above to whoever runs there. "Crossplane for GPU fleets, Cluster API for the machines underneath them" is not a diplomatic compromise — it is a literal description of how the layers compose. Modelplane's InferenceClusters need real clusters with real GPUs attached; a Cluster API management cluster with a GPU-capable provider is the obvious thing to put underneath.

The strongest counter-argument deserves a straight answer: Crossplane can provision Kubernetes clusters too — providers expose EKS, GKE, and AKS as managed resources, and a composition can stamp out clusters like any other infrastructure. If one control plane can do everything, why run two? Two reasons. First, what Crossplane provisions there is a cloud vendor's managed cluster product — an API call to EKS — not machine-level lifecycle on arbitrary hardware. If your fleet is bare metal or owned Hetzner servers, there is no managed-cluster API to call; you need the layer that does bootstrap, kubeadm, health checks, and rolling node upgrades itself, and that layer is Cluster API. Second, revealed preference: the Crossplane ecosystem's own flagship, Modelplane, drew its boundary above the cluster, modeling capacity rather than machine lifecycle — a tacit acknowledgment that cluster creation is someone else's well-solved problem.

And the maturity asymmetry in the comparison table — Crossplane CNCF-graduated, Cluster API "merely" a SIG subproject — argues less than it appears to. Graduation measures a project's governance and adoption as a standalone CNCF entity; Cluster API lives inside the Kubernetes project itself, under SIG Cluster Lifecycle, which is not a junior league. Neither status makes one project a safer answer to the other's problem.

Where bex Draws Its Line

bex is an open-source, self-hosted PaaS: push a git repo, get a running HTTPS service on machines you own. Its non-goals are written down just as deliberately as Cluster API's, and one of them is multi-cloud abstraction — bex is explicitly not building a universal control plane over many providers. That single sentence decides the Crossplane question.

What a self-hosted PaaS needs from the infrastructure-as-API idea is two layers, both narrow:

  • Machine lifecycle as an API. Clusters on owned hardware have to come from somewhere, survive node failures, and upgrade without ceremony. That is Cluster API's exact scope — and its narrowness is precisely what makes it match a platform whose value is depth on machines you own (a Hetzner box at a flat monthly price) rather than breadth across clouds you rent.
  • Application intent as an API. A developer — or an AI agent — declares "this repo, this domain, these resources," and the platform reconciles it. That is an App-style custom resource above the cluster, purpose-built for deploy-and-operate, not a general-purpose composition engine.

Between those two layers, bex deliberately builds nothing Crossplane-shaped: no XRD-based abstraction over cloud portfolios, no composition layer promising the same resource on any provider. Not because that layer is bad — because it solves a problem a self-hosted PaaS has chosen not to have. Abstraction layers cost you the thing self-hosters came for: knowing exactly what is running where, at what price.

When should you reach for Crossplane anyway? Genuinely multi-provider resource needs — a platform team offering one database API across AWS and GCP to dozens of product teams — or fleet-level GPU placement of the kind Modelplane just made open source. If that is your problem, Crossplane is the mature, graduated, well-governed answer to it. It composes cleanly on top of the same clusters either way.

The deeper agreement matters more than the boundary dispute. Both projects — and bex — are built on the same conviction the CNCF's March 2026 post articulated: the platforms that survive the AI-agent era are the ones whose entire operational surface is a typed, declarative, machine-readable API. Agents cannot click dashboards. They can reconcile desired state. Crossplane answers that for everything above the cluster; Cluster API answers it for the cluster itself; a PaaS answers it for the application. The question was never whether infrastructure should be an API. It was always which API you owe your users — and the best projects in this space are the ones that answer narrowly, in writing.


Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, with Cluster API managing the machines underneath. Star the repo on GitHub or deploy your first app today.

Related articles

Run this on infrastructure you own

bex is the open-source, AI-native Render alternative — push a git repo and get a running HTTPS service on your own machines.

Get started with bex