Skip to main content

CloudNativePG vs Zalando vs StackGres: Why bex Chose CNPG for Managed Postgres

8 min readDora NodaDora Noda
Share

Supabase hired a maintainer specifically to fix self-hosting in late 2025, then opened a public GitHub discussion asking the community what's still broken. A year later, the honest answer for anyone running docker compose up from the self-hosting repo hasn't changed: no managed backups, no point-in-time recovery, no branching, no multi-project Studio. Meanwhile, a different open-source platform — bex, the one this blog is written for — already solved "managed Postgres on Kubernetes" for its own tenants, and picked a Postgres operator to build it on. Here's the operator decision, made concrete, and what it exposes about the gap Supabase's self-hosting docs still haven't closed.

The Three Operators, Head to Head

Three projects compete to run the HA-Postgres layer under a Kubernetes-native platform: CloudNativePG, the Zalando Postgres Operator, and StackGres. They solve the same problem — keep a Postgres cluster alive, failing over automatically, backed up — but they disagree on how much of the surrounding stack they own and what license you accept to run them.

CloudNativePGZalando Postgres OperatorStackGres
GovernanceApache 2.0, CNCF Sandbox project (EDB-backed)Apache 2.0, maintained by Zalando (an e-commerce company, not a database company)AGPL, OnGres's primary commercial product
HA architectureNative — failover driven directly through the Kubernetes API, no external dependencyPatroni + StatefulSets — the original pattern this whole category is built onPatroni-based, bundled inside an opinionated all-in-one stack
What ships with itThe operator and CRDs only — HA, backup/PITR via WAL archiving or Volume SnapshotsThe operator only — same minimal footprint as CNPGPgBouncer, Envoy proxy, Fluentd logging, Prometheus monitoring, and a web UI, all bundled
Momentum (2026)~9K GitHub stars, most active of the three, CNCF sandbox trajectoryBattle-tested at Zalando's own scale (thousands of clusters), but community activity has slowedCompany-driven, so well-funded, but a smaller install base outside OnGres customers

CNPG is the right call for bex's managed-Postgres product specifically, for reasons that come down to fit, not just popularity. It's Apache 2.0 and CNCF-governed — StackGres's AGPL license is a real blocker for a platform redistributing the operator to every tenant cluster. Its HA model needs nothing beyond the Kubernetes API itself, no Patroni to operate on top of the operator. And the part that actually decided it: every axis of a managed-database plan — compute, availability, durability — maps 1:1 onto a CNPG CRD field. When a product spec matches an operator's data model that closely, building on anything else means fighting the tool.

That doesn't make the other two wrong choices in general. Zalando is still the better pick if you're already running Patroni elsewhere and want one consistent failover story across your fleet, or if you want the operator with the longest production track record at real scale — Zalando's own deployment predates CNPG by years, and "battle-tested since before Kubernetes operators were a mature pattern" is worth something CNPG's newer CNCF trajectory hasn't had time to match yet. StackGres is the better pick if you want the ops surface — pooling, monitoring, a UI — assembled for you rather than wired together from separate pieces, and you're comfortable with AGPL (which matters far more if you're redistributing the operator than if you're just running it internally). bex's decision was specific to a platform that redistributes the operator into every tenant namespace, where AGPL and "one more thing to operate" both weigh heavier than they would for a single internal cluster.

From Operator Choice to an Actual Product

Picking an operator is the easy 20%. The other 80% is turning "CNPG is installed" into "a tenant can click Create Database and get a connection string" — and this is where most self-hosting write-ups stop short. bex's Database custom resource is the concrete version of that translation, shipped and accepted as of this post, and it's a direct case study in what "steer tenants toward one operator" looks like as actual code rather than a documentation footnote.

The design starts from a three-axis plan model, because a managed-Postgres tier isn't one dial — it's compute, availability, and durability moving independently:

AxisCNPG field it maps to
Compute (RAM/CPU)spec.resources.requests/limits
Availabilityspec.instances (replica count, anti-affinity)
Durabilityspec.backup.barmanObjectStore / ScheduledBackup

And the shipped MVP tiers turn that into three real plans, sized to fit a single 8GB node:

PlanComputeStorageBackup
free256Mi / 0.1 CPU1Ginone — 30-day TTL sweep, so "free forever" can't quietly eat the cluster
basic-256mb256Mi / 0.1 CPU1Gidaily ScheduledBackup
basic-1gb1Gi / 0.5 CPU5Gidaily ScheduledBackup

Each Database resource projects to a CNPG Cluster inside the tenant's own namespace, which is what makes the isolation model free rather than bolted on. The tenant's existing NetworkPolicy, ResourceQuota, and RBAC already apply, because the database is just another workload living where the tenant's other resources already live.

Connectivity follows the same "no per-tenant infrastructure" discipline: an internal ClusterIP service for in-cluster apps, and a single wildcard Traefik TCP router doing SNI + TLS passthrough for external access. One shared :5432 entrypoint routes every tenant's public database, instead of provisioning a load balancer per database.

What Self-Hosted Supabase Still Doesn't Have

Put next to that, the gap in Supabase's self-hosting story is specific, not vague. Supabase's own docs are direct about the boundary: platform-only features — branching, managed backups and PITR, advanced metrics, the multi-project Studio — are unavailable in the self-hosted Docker Compose configuration. That's not a rough edge that'll get smoothed over in a patch; it's an architectural line Supabase draws between the hosted product and the thing you can run yourself.

The community has been asking for the obvious fix since at least GitHub discussion #31147: wire Supabase's Postgres image into CNPG instead of the plain Compose container, so self-hosters inherit CNPG's declarative backup, PITR via Volume Snapshots, and failover for free. It's a good idea — and more than a year after Supabase brought on a maintainer explicitly to work on self-hosting, it's still a discussion thread, not a shipped Helm chart. Runbooks for self-hosted PITR today mean reaching for WAL-G by hand — the same tool Supabase's own managed platform uses internally, just without the platform wrapped around it.

That's the concrete cost of "operator choice as homework": a self-hoster gets Postgres, Auth, PostgREST, Storage, Realtime, and Kong wired together by Docker Compose, and then has to independently research, choose, and wire in an HA operator themselves if they want backups that survive a node failure. Compare that to a Database CRD that already picked CNPG, already maps a plan to its CRD fields, and already ships a connection string — the difference isn't operator quality, all three are legitimate projects. It's whether the platform did the integration work or left it as an exercise for every tenant.

The Honest Caveat

This wasn't always bex's story to tell. Managed databases used to be a stated non-goal for the project — tenant data was explicitly out of scope, on the theory that a self-hosted PaaS shouldn't also be a database vendor. That changed once Render parity became the actual product goal: Render sells managed Postgres as a first-class, standalone resource, and a platform claiming to be an open, self-hostable Render alternative has to offer the same thing to be a real substitute, not a subset.

It's also not finished. The MVP scope explicitly defers HA (a instances: 3 failover tier needs a worker pool bigger than the single node it currently targets), PITR, storage autoscaling, and metering to later work — the free and basic tiers ship today; the tier that actually delivers on "point-in-time recovery," the thing Supabase self-hosters are missing most, is still ahead. The gap this post describes against Supabase isn't fully closed on bex's side either — it's closed further, on a concrete, shipping timeline, which is a different claim than closed.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, with Render-compatible managed Postgres built on CloudNativePG. Star the repo on GitHub or deploy your first database today.

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