Skip to main content

Nomad vs Cluster API: Why a 1-3 Week Setup Win Still Loses for a Multi-Tenant PaaS

9 min readDora NodaDora Noda
Share
On this page

HashiCorp's own numbers say Nomad goes from proof of concept to production in 1-3 weeks, regardless of company size. A comparable Kubernetes deployment — monitoring, RBAC, ingress, GitOps all wired up — takes teams new to it 2-6 months. That's not a marketing rounding error; it's the honest gap between a single Go binary with no etcd, kubelet, kube-proxy, or CoreDNS, and the five-process control plane Kubernetes makes you stand up before a workload runs. If you're picking an orchestrator for your own app, that gap should decide the question outright. If you're building a git-push, multi-tenant PaaS that other people's apps run on, it's the wrong axis to evaluate on — and this is a grounded look at exactly what a platform gives up trading Cluster API's Kubernetes-native machine lifecycle for Nomad's simpler model, without pretending Nomad's speed isn't real.

What Nomad actually gets right

Nomad's pitch isn't hype. It's one Go binary that runs as both client and server — no etcd, no separate scheduler process, no CoreDNS to keep alive. A three-node cluster reportedly comes up in about 10 minutes; a comparably functional Kubernetes cluster with networking wired in takes 45 minutes or more. Server and client processes combined run under 100 MB of RAM with no external database dependency, against the 2-4 GB a Kubernetes control plane (API server, etcd, scheduler, controller manager) needs before a single application pod starts.

Job specs are HCL, not a CRD graph five files deep. There's no separate CNI daemon set, no admission webhook chain to debug when a pod won't schedule. For a team under 50 services without a dedicated platform engineer, that's a real, not cosmetic, reduction in what can break and who has to understand it to fix it. This is the same argument Kamal 2 makes against Kubernetes for a fixed, small, slowly-changing set of Rails processes — simpler tools are the correct engineering choice for the workload shape they're built for, not a placeholder on the way to something heavier.

The question a PaaS builder actually has to answer isn't "is Nomad simpler than Kubernetes" — obviously yes. It's whether that simplicity survives contact with the specific job a multi-tenant, git-push platform needs its orchestrator to do: give tenants, not operators, a self-service way to declare what they need and get it, safely isolated from every other tenant on the same fleet.

The capability gap, row by row

Here's where Nomad's monolithic simplicity and a multi-tenant PaaS's requirements actually diverge — each row is a capability Cluster API inherits for free from the Kubernetes ecosystem underneath it, and what Nomad has instead:

CapabilityCluster API (Kubernetes-native)Nomad
CNI ecosystemAny CNI plugin — Cilium, Calico, Flannel — with NetworkPolicy, and increasingly eBPF-based L7 policy and DNS-aware controlsSupports the CNI spec, but the plugin ecosystem built for Nomad is thin; per HashiCorp's own docs, cross-node service networking commonly still leans on Consul Connect rather than a CNI-native mesh
CSI / dynamic storage provisioningCSI drivers (e.g. CloudNativePG on Hetzner-backed storage) create, resize, and destroy volumes on demand as part of a tenant's declared specNomad "can utilize CSI volumes, but it cannot automatically create, destroy, or manage them" — volumes have to be provisioned externally, then registered by hand
Per-tenant routingGateway API's HTTPRoute/Gateway objects give each tenant a namespaced, declarative routing object with RBAC on who can edit itTraefik's Nomad provider reads one namespace (or namespaces) setting for service discovery — there's no per-tenant routing object a tenant can safely declare themselves
CRD-based tenant self-serviceA tenant's manifest is a CRD (a Cluster, an App) that a controller reconciles — this is the entire mechanism kro and Crossplane build onNomad has no extensible API to build a tenant-facing CRD equivalent on; a tenant's job spec is a flat HCL file the platform's own tooling has to template and mediate
Node failure recovery at fleet scaleMachineHealthCheck continuously watches every node across every workload cluster and replaces failures automaticallyNomad's own scheduler reschedules failed allocations; recovering a dead node itself is not part of the same reconciliation loop

The CRD row is the one that actually decides this for a PaaS. Kubernetes' API server isn't just a scheduler with a REST front end — it's an extensible object store with RBAC, watch semantics, and a controller pattern that lets a platform hand a tenant a narrow, safe surface (declare a Cluster CR, get a CloudNativePG-managed Postgres instance; declare an App, get a running HTTPS service) without giving them shell access to anything. Nomad's HCL job spec is a deploy artifact, not an API a tenant safely holds a scoped credential against. Building tenant self-service on Nomad means the platform has to build and operate that whole abstraction layer by hand — templating HCL, enforcing quotas, mediating access — instead of inheriting it from the orchestrator's own object model.

What multi-tenant Nomad looks like in practice today

Nomad does have a real multi-tenancy story, and it's worth being fair to it rather than pretending it doesn't exist: Nomad Enterprise namespaces isolate jobs per tenant, ACL tokens scope who can read or write which namespace, and HashiCorp has documented production deployments — Exact Sciences runs multi-tenant workloads across the HashiStack (Nomad, Consul, Vault) with automated compliance built on exactly this namespace-and-ACL model. Consul Connect layers mTLS and service-mesh routing on top, and Traefik's Nomad provider can scope service discovery to a tenant's namespace.

What that stack doesn't give a tenant is an API to declare infrastructure against. Namespaces and ACL tokens are an isolation boundary the operator configures per tenant, not an extensible object model the tenant declares new resource types into. Adding a new self-service primitive — "let a tenant request a Postgres instance with backups" — means the platform team builds a bespoke integration against Nomad's fixed job-spec schema and Consul's KV store, one primitive at a time. On Cluster API's Kubernetes base, the same primitive is a new CRD and a controller watching it, using the identical reconciliation pattern every other resource in the cluster already uses — CloudNativePG's Cluster CRD, Cluster API's own Machine CRD, and a hypothetical tenant-facing App CRD are all the same shape of object, reconciled the same way, inheriting RBAC and watch semantics from the same API server. That uniformity is what a growing self-hosted PaaS actually needs as it adds primitives over years, not a one-time setup-speed win measured in weeks.

The licensing variable a control-plane decision can't ignore

There's a second, less technical reason this matters for a platform choosing what to build its control plane on for years, not months: Nomad Community Edition ships under HashiCorp's Business Source License, not an OSI-approved open-source license — it restricts competing commercial use, and IBM's 2025 acquisition of HashiCorp for $6.4 billion (finalized February 27, 2025) hasn't softened that stance. HashiCorp has continued pursuing legal claims against OpenTofu — the community fork of Terraform that emerged after the same BSL switch — alleging contributors incorporated proprietary code post-fork, and under IBM's ownership that posture looks more likely to harden than reverse.

Cluster API and the Kubernetes project it extends are Apache 2.0, governed by CNCF, with no single vendor able to change the license underneath every platform built on it overnight. For a self-hosted PaaS that plans to still be running the same control plane in five years, "who owns the license and can they change the rules on us" is not a hypothetical the orchestrator choice can skip past — it's the same category of risk 38% of Terraform users are already migrating away from with OpenTofu.

"Simpler to run" and "the right substrate to hide from tenants" aren't the same claim

The framing that makes Nomad look like it wins this comparison collapses two different questions into one. "Which orchestrator is simpler to operate" and "which orchestrator is the right substrate for a platform whose entire product is hiding the orchestrator from tenants" have different answers, because a PaaS's job isn't running the orchestrator well for itself — it's exposing a narrow, safe, self-service surface to other people on top of it. Nomad wins the first question outright: less RAM, fewer moving parts, a job spec you can read top to bottom in five minutes. Cluster API wins the second, because the thing a multi-tenant PaaS actually needs — a tenant declares a CRD, a controller reconciles it, isolation and routing and storage all inherit from an extensible API rather than getting hand-built on top of a flat job spec — is Kubernetes' actual design center, not a feature bolted onto Nomad's namespace-and-ACL model after the fact.

That's also why Cluster API's own "1-3 weeks to production" number doesn't matter to bex the way it matters to a team standing up their own workload cluster: the control-plane bring-up cost is bex's job to absorb once, on a Cluster-API-provider-Hetzner fleet, not a cost every tenant re-pays. A tenant pushes a git repo and gets a running HTTPS service; the CRD graph, the CSI-provisioned storage, the Gateway API routing all sit underneath, doing exactly the multi-tenant self-service work Nomad's simpler model would have made the platform build by hand.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, with a Cluster-API-managed control plane doing the tenant isolation, storage provisioning, and routing a simpler single-binary orchestrator would leave as the platform's own problem to solve. Star the repo on GitHub or deploy your first app today.


Sources

All figures and quotes cited above are drawn directly from the linked sources.

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