Skip to main content

Fly Postgres Is a Thin Provisioning Layer: The Exit Math When 'Managed' Stops at Replication and Backups

11 min readDora NodaDora Noda
Share
On this page

Pickuma's 2026 Fly.io review contains the single most useful sentence ever written about Fly Postgres: it is "a thin management layer over unmanaged Postgres instances." Fly provisions the machines, configures replication, and hands you backup tooling — but connection pooling, query monitoring, automated failover, and dashboard polish are yours to build. If you priced your database assuming "managed" meant "handled," this post is the bill for the difference.

The exit math up front: a small-production HA setup (primary plus standby, ~10 GB each) costs roughly $11/month in infra on classic Fly Postgres with every gap DIY'd, ~$38/month on Fly's Managed Postgres (MPG) with the gaps closed, and ~$0 in marginal infra on CloudNativePG running on nodes you already pay flat-rate for — with the cost moved into setup and operation instead of a meter. The table below shows the full accounting; the rest of the post prices each missing piece and maps it to its explicit equivalent.

Two Postgres products, one confusing label

The first thing to get straight is that "Fly Postgres" now names two different products, and the Pickuma verdict applies to the older one.

Classic Fly Postgres is what the review describes: Fly's own docs call it "a Fly app with flyctl sugar on top to help you bootstrap and manage a database cluster." It boots machines, wires up streaming replication, and gives you snapshot tooling. Pooling, query-level observability, and hands-off failover are not included — you run PgBouncer yourself and monitor through your own stack. This matches Fly's own long-standing framing, memorably stated by a Fly engineer years ago: Fly Postgres is automated, but not managed.

Managed Postgres (MPG) is Fly's newer database-as-a-service answer to exactly this criticism: two-node HA with automatic failover, a two-node PgBouncer setup, automatic backups, and performance monitoring. The floor price for that closure is real, though — community reports put the Starter plan at ~$38/month for the mandatory two-node HA configuration, which cannot be scaled down to a single node.

So the honest version of the Pickuma verdict in late 2026: classic Fly Postgres is a thin provisioning layer, and the fully managed tier starts at roughly 3.5x the infra cost of the thin one. Every team on the classic product is implicitly answering the question "is the DIY worth the spread?" whether they ran the numbers or not. Let's run them.

The gap inventory, priced one by one

Pickuma names four missing pieces. Here is what each one actually costs a team to fill — in infra, labor, or both.

1. Connection pooling. Serverless and multi-instance apps exhaust Postgres connection limits fast, which is why every managed competitor ships a pooler. On classic Fly Postgres you run PgBouncer yourself: either a tiny dedicated Machine (another ~$2–4/month plus its own care and feeding) or a sidecar next to each app instance, plus the transaction-mode configuration and the debugging session the first time prepared statements misbehave through it. Railway and Render include pooling in the managed price; MPG includes a two-node PgBouncer pair. DIY cost: small in dollars, real in on-call surface.

2. Query monitoring. "Which query got slow after Tuesday's deploy?" has no answer inside classic Fly Postgres beyond what you instrument. The DIY path is your own observability stack pointed at Postgres — pg_stat_statements, log shipping, a dashboard you build and maintain — or a paid APM seat. Either way the cost is labor plus whatever your metrics backend charges to ingest the series. This is the gap teams feel latest and resent most: everything works until the first slow-query incident, at which point the absence of built-in query insights turns a 20-minute diagnosis into a forensic dig through logs you may not even be retaining.

3. Automated failover. Classic Fly Postgres gives you replication and failover tooling (fly pg failover exists), but promoting a standby after a primary failure is an operation you perform or script — it is not the platform noticing and acting while you sleep. The DIY substitute is a runbook: health checks, promotion steps, connection-string updates, and a rehearsal schedule. MPG and Render's HA tiers do this automatically; Railway's Postgres-HA template uses Patroni with sub-10-second automatic failover. DIY cost here is almost entirely risk-shaped: $0 most months, then one very bad night that determines whether your runbook was real or aspirational.

4. Dashboard polish. Pickuma notes Fly's web UI trails its CLI for region-level deployment, machine scaling, and volume management. This sounds cosmetic until a non-CLI-native teammate needs to answer "is the database healthy?" at 2 AM. The DIY substitute is either CLI fluency across the whole on-call rotation or — again — your own dashboard. Railway and Render ship the graphical answer; on Fly, flyctl is the interface and the docs assume distributed-systems literacy to drive it.

Add it up and the pattern is clear: every gap is either a small machine you run, a system you build, or a risk you carry. None of them is fatal. All of them are recurring.

The exit-math table

Price a typical small-production shape — primary plus standby in one region, ~10 GB of data per node — three ways. Fly figures use Pickuma's measured rates: shared-cpu Machines at ~$3.88/month per 512 MB instance running continuously, volumes at $0.15/GB-month.

Classic Fly PostgresFly Managed Postgres (MPG)CloudNativePG on owned nodes
Compute2 × 512 MB shared-cpu ≈ $7.762-node HA cluster ≈ $38Share of flat-rate nodes ≈ $0 marginal
Storage2 × 10 GB × $0.15 ≈ $3.00Included in planShare of attached disks ≈ $0 marginal
Infra total~$11/month~$38/month~$0/month marginal
PoolingDIY (PgBouncer machine/sidecar)Included (2-node PgBouncer)Pooler CR (PgBouncer)
MonitoringDIY (own stack)Included (metrics + portal)PodMonitor → Prometheus
FailoverManual / runbookAutomaticAutomatic (operator-promoted)
BackupsSnapshot tooling (you schedule)Automatic + recoveryWAL archiving → object storage + PITR

Two deltas matter. First, the $27/month spread between classic and MPG is the market price of the four gaps — pooling, monitoring, automatic failover, and managed backups, bundled. If your DIY already covers all four reliably, you're arbitraging Fly's menu successfully. If it covers two of four, you're paying in risk what MPG charges in dollars.

Second, the CloudNativePG column has no meter because the cost moved, not vanished. Running the CNCF-graduated operator on Hetzner nodes you're already paying flat-rate for adds ~$0 in marginal infra — but the pooling, monitoring, failover, and backup rows are explicit operator choices you configure: a Pooler CR, monitoring with a PodMonitor, replica counts with fencing rules, a scheduled-backup object pointing at your S3-compatible bucket. The difference from classic Fly Postgres isn't that the work disappears; it's that the work is declared, versioned, and reconciled instead of being a wiki runbook and a sidecar you hope someone remembers.

One more cost belongs in honest exit math: the migration itself. Moving off Fly Postgres is a solved problem — pg_dump/pg_restore for small databases with a maintenance window, or logical replication with a monitored catch-up phase and clean cutover (one documented Fly-to-RDS walkthrough reports ~10 minutes of actual downtime). Budget an engineer-day for the small path, an engineer-week with rehearsal for the zero-drama path. That one-time cost is almost always smaller than a year of the wrong recurring column.

Where the math moves

A single worked example can mislead, so here is the sensitivity around it — the variables that change which column wins.

Single-node dev flips the ranking. Drop the standby and shrink to one 256 MB Machine (~$1.94) plus a 10 GB volume ($1.50) and classic Fly Postgres costs ~$3.50/month — unbeatable, because MPG has no single-node tier at all (two-node HA is mandatory). If your database is a dev/staging instance that can tolerate downtime, the thin layer is the cheapest correct answer and the gaps barely matter. The exit question only starts at production HA.

Multi-region multiplies the thin layer linearly. Each Fly read replica is a separate Machine with its own volume cost, and cross-region query latency over the WireGuard mesh runs ~100–240 ms depending on the pair (Pickuma measured 200–240 ms Tokyo/Sydney to Amsterdam). A primary plus two regional replicas roughly triples the classic column while adding latency your app must be designed around — cacheable reads colocated per region, writes pinned home. MPG's managed story is simpler but priced per managed cluster, so the regional math deserves its own spreadsheet row rather than an extrapolation.

Volume growth favors flat-rate disks. At $0.15/GB-month, Fly storage is reasonable — but it meters every gigabyte forever, while a Hetzner node's attached storage is a flat increment whether Postgres uses 10 GB or 100 GB. The bigger the dataset, the more the metered-vs-flat gap compounds, independent of compute.

Team time dominates everything above. The infra spread between classic and MPG is ~$27/month — roughly fifteen minutes of a loaded engineer's time. If your DIY pooling, monitoring, and failover runbook consume more than an hour a quarter in maintenance, incident response, or rehearsal, MPG is cheaper even before you value the risk reduction. The teams for whom classic wins are the ones whose DIY is already built, already rehearsed, and amortized across many databases — i.e., teams already operating like a platform team. Which raises the question the next section answers: if you're operating like a platform team, why rent the thinnest layer?

The same pieces, stated explicitly

This comparison is worth making mapping-by-mapping rather than vibes-by-vibes, because the point is structural: self-hosting on owned nodes doesn't eliminate the four gaps — it converts each from an absent feature into a declared choice.

  • Pooling → Pooler CR. CNPG's built-in PgBouncer integration is a Kubernetes object with replica counts, pool modes, and auth config in git. Same PgBouncer you'd run on Fly — but reconciled by a controller instead of babysat as a pet Machine.
  • Monitoring → PodMonitor + Prometheus. CNPG exposes Postgres metrics out of the box and ships the monitoring stanza to scrape them. Same dashboards you'd build against Fly — but the scrape target and exporter lifecycle are operator-managed.
  • Failover → automatic promotion. Primary failure promotes a replica with configurable sync-replica and fencing semantics (documented deployments target ≤10s RTO). Same outcome as MPG's automatic failover — but the policy is yours to read in the Cluster spec.
  • Backups → scheduled WAL archiving + PITR. Barman-based backups to any S3-compatible bucket with point-in-time recovery. Same safety as managed automatic backups — but the bucket, schedule, and retention are explicit fields, not plan fine print.

None of this is free — the operator, the bucket, and the Prometheus stack are yours to run. The honest pitch for the self-hosted column is not "cheaper" but "legible": every row in the table is a decision you made and can audit, on hardware with a flat bill. For a team already carrying DIY pooling, DIY monitoring, and a failover runbook on classic Fly Postgres, CNPG on owned nodes is arguably less total work than the status quo, because the runbook becomes YAML and the sidecars become reconciled objects.

Stay or exit, and how to decide

Three sentences decide it. Stay on classic Fly Postgres if you're single-region, CLI-comfortable, and the four gaps are already DIY'd and rehearsed — you're successfully arbitraging the menu. Upgrade to MPG if any gap is currently a risk you carry rather than a system you run — $38/month is cheap incident insurance against the 2 AM promotion you'll otherwise perform by hand. Exit to an operator-run Postgres on owned nodes if you're already operating like a platform team and want the bill flat and the choices explicit.

The deeper lesson generalizes beyond Fly. "Managed" is not a binary — it's a bundle, and every vendor draws the bundle boundary somewhere different. Fly drew it at provisioning plus replication; Render and Railway drew it wider; MPG exists because enough teams asked Fly to redraw it. Before you migrate to any platform, list the bundle boundary in writing. Before you migrate away, price the gaps, not the sticker. The team that knows exactly which Postgres features it's renting versus owning never pays the premium for a label — in either direction.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. 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