# Fly.io Managed Postgres alternatives: $38 a month is the floor, not the bill

> Fly Managed Postgres starts at $38/month per cluster, adds $0.28 per provisioned GB, and is deliberately unreachable from the public internet. Here is what that costs a side project, why the private networking is defensible, and when to run the database somewhere else.

Published: 2026-08-27
Canonical: https://layerbase.com/blog/fly-postgres-alternative

Short version: Fly Managed Postgres starts at $38/month for the smallest cluster, adds $0.28 per provisioned GB per 30-day month for storage, and has no hobby tier. It is also not reachable from the public internet by design, so anything outside your Fly private network gets there through a proxy or a WireGuard tunnel. Both of those are defensible decisions if you live on Fly. They are expensive decisions if you have three small databases and two of them are for CI.

Fly.io is a good platform run by people who clearly enjoy the hard parts. Managed Postgres is a real improvement on the old unmanaged Postgres app, and if your entire stack runs on Fly, the private-network design is a feature rather than an obstacle. I am not going to pretend the reachability model is a mistake. It is a coherent choice.

It is also a choice with a bill attached, and the bill has a floor.

## The price ladder

Verified 2026-08-27 against [Fly's Managed Postgres docs](https://fly.io/docs/mpg/):

| Plan        | Monthly    |
| ----------- | ---------- |
| Basic       | **$38**    |
| Starter     | **$72**    |
| Launch      | **$282**   |
| Scale       | **$962**   |
| Performance | **$1,922** |

Storage is separate: **$0.28 per provisioned GB per 30-day month**, capped at 1 TB. Note "provisioned", not "used". You pay for the volume you asked for.

There is one more line that appeared this year and is easy to miss: inter-region private network usage has been billed since February 2026. If your app and your database are in different regions, or you fan out across regions, that traffic is now a charge rather than a rounding error. Worth checking before you assume a multi-region layout is free.

HA, backups, and connection pooling are included in the plans rather than sold as add-ons, which is the right way to do it and deserves saying.

## Why the floor is the story

$38 is not expensive for a production database. Compared to what a comparable managed Postgres costs elsewhere, it is fine.

The problem is that $38 is the **smallest** thing you can buy, and databases do not come one at a time.

Count the ones you actually have. A side project. Its staging environment, because you learned that lesson already. A database for CI, because tests against a shared instance produce the flakiest bug reports in existence. Maybe a scratch one for a migration you are nervous about. That is four databases. On Fly Managed Postgres that is $152 a month plus storage, and three of those four are idle almost all of the time.

There is no hobby tier for MPG. There is no scale-to-zero. The floor applies per cluster, and a cluster that nobody queries all weekend costs exactly what a busy one costs.

That is where the shape of the pricing stops matching the shape of the work. Not at your production database, which is worth $38 and more. At the three around it.

## The reachability tax

From Fly's own documentation: "Because your MPG Cluster runs within your Fly.io private network, it's not accessible over the public internet."

That is the design, and it is a genuinely defensible one. A database that is not on the internet cannot be scanned, credential-stuffed, or found by someone's Shodan query. Plenty of expensive incidents start with a Postgres that answered the phone when it should not have.

The practical consequences, though, land on you:

- Fly's own [create and connect guide](https://fly.io/docs/mpg/create-and-connect/) covers the supported ways in: `fly mpg connect` opens a session against the cluster, and `fly proxy` forwards it to a port on your own machine, so local `psql` works. Fine for a human.
- Anything that is not a human on your laptop needs the tunnel too. A GitHub Actions job, a data pipeline on another host, a BI tool, an ORM Studio running in someone else's environment, a colleague's SQL client.
- The official escape hatch is the [`fly-apps/fly-mpg-proxy`](https://github.com/fly-apps/fly-mpg-proxy) app: you deploy it, and it exposes your cluster on a public `*.fly.dev` hostname. Read its configuration before you deploy it, because it ships allowing `0.0.0.0/0`. You have now put the database on the internet, with an extra hop, after the platform spent real effort keeping it off.

For reference when you are wiring any of this: the cluster hostnames are `direct.<id>.flympg.net`, which bypasses PgBouncer, and `pgbouncer.<id>.flympg.net`, which does not. The default user is `fly-user` and the default database is `fly-db`.

Being fair about it: if your app runs on Fly, none of this is a tax at all. Your app is already on the private network, it connects directly, and the tunnel is something you touch a few times a year when you need to poke at a row. The cost only shows up when the database has consumers that do not live on Fly, and that is a "what does your stack look like" question rather than a "who is right" question.

One more thing to know if you are inventorying: Redis on Fly is Upstash. It is a partner integration, not a Fly-operated engine, with its own account, its own pricing model, and its own dashboard. So the "one vendor" story is a little less one-vendor than it looks the moment you add a cache.

## What Layerbase does differently

**Flat prices with a floor of zero.** Free is $0 with no card: 2 databases, 5 GB, 9 engines. Solo is $5/month for 2 databases and 10 GB. Pro is $15/month for up to 10 databases, 25 GB, and every engine on our shared cloud. The scratch database and the CI database cost nothing extra because they fit in the plan you already bought, and idle databases sleep and wake on connect instead of billing you for existing.

**Storage is in the plan, not per GB.** If you need more, pool blocks are $10/month for +1 GB RAM, +1 vCPU, and +25 GB storage. Still flat, still a number you can say out loud.

**Publicly reachable, with TLS, on purpose.** Your database has a hostname anything can connect to, which means CI connects, a teammate's client connects, and a job on another host connects, all without a tunnel. If you want the stricter posture back, Postgres on Pro supports client certificate authentication with a per-database CA and one-click rotation, which is a tighter control than "the network is private" and does not require a proxy app to relax.

**19 engines on one account.** The cache is a dropdown, not a second vendor with a second invoice.

Backups: a manual slot on Free, every 12 hours on Solo and Pro, kept 7 days on Solo and 30 on Pro. Point-in-time recovery is available on Pro and above and requires the database to be pinned always-on, since a sleeping database is not producing a write-ahead log to archive.

## The move, with real commands

The app stays on Fly. Only the connection string changes.

The [Fly.io migration page](/migrate/fly) walks through both paths and carries the current wording for each, because this is the one source where the reachability model decides the method rather than the connection string. The short version is below.

**1. Dump and load from inside the private network.** The simplest path is to do the copy from a machine that is already on the network, since it has public egress out to the destination:

```bash
fly ssh console -a my-app
```

```bash
# inside the machine
apt-get update && apt-get install -y postgresql-client   # if pg_dump is not in your image

pg_dump "postgres://fly-user:<password>@direct.<id>.flympg.net:5432/fly-db" \
  --no-owner --no-acl \
  | psql "postgresql://layerbase:<password>@<host>.cloud.layerbase.dev:5432/appdb?sslmode=require"
```

Use the `direct.` hostname rather than the `pgbouncer.` one for the dump. A transaction pooler and a long-running `pg_dump` are not friends.

**2. Or run it from your laptop through the proxy.** If you would rather not install anything in the machine image, forward the cluster to localhost and dump from there:

```bash
fly mpg connect          # interactive psql session, good for a sanity check
# or forward the port and run pg_dump against 127.0.0.1
```

Same command, `127.0.0.1` in place of the `flympg.net` host. It is slower, because every byte goes out through your machine and back, but it needs nothing on the Fly side.

**2b. Or, if you want the guided wizard, deploy Fly's MPG proxy first.** The wizard runs from our servers, so it needs a publicly reachable front door. Fly publishes one. Three things bit us running this on 2026-09-01, and all three fail quietly rather than loudly:

```bash
fly launch --from=https://github.com/fly-apps/fly-mpg-proxy \
  --secret CLUSTER_ID=<your-cluster-id>
```

- **`fly launch --from` regenerates `fly.toml` with HTTP defaults.** That drops the TCP services the proxy needs, so the app deploys, reports healthy, and nothing ever answers on the Postgres port. Restore the repository's `[[services]]` stanza and `fly deploy` again before you go looking for anything else.
- **Allocating a dedicated IPv4 does not remove the shared one.** After `fly ips allocate-v4` the app has both, DNS serves both records, and connections succeed or fail depending on which one the client resolved. Run `fly ips list`, then `fly ips release <shared-ip>`.
- **The pasted connection string needs `?sslmode=disable`.** The `direct.` endpoint speaks no TLS through the proxy, so libpq's default handshake dies before it gets anywhere. Take the `direct.<cluster>.flympg.net` string, swap in the proxy hostname, keep port 5432, and append the parameter:

```
postgresql://fly-user:<password>@mpg-proxy-something.fly.dev:5432/fly-db?sslmode=disable
```

The proxy ships allowing every address, so restrict its `ip-whitelist.txt` or destroy the app once the copy finishes.

**3. Point the app at the new database.**

```bash
fly secrets set DATABASE_URL="postgresql://layerbase:<password>@<host>.cloud.layerbase.dev:5432/appdb?sslmode=require"
```

Setting a secret triggers a redeploy. That is the migration.

**4. Verify before you delete anything.** Row counts on both sides, then run the app against the new database for a few days before you tear down the cluster. Storage is billed on what you provisioned, so the old cluster keeps charging until it is actually gone, but that is a cheap week of insurance.

## Where Fly still wins

I would not move a database off Fly reflexively, and there are two cases where staying is clearly correct.

**Single-region app-to-database latency.** If your app runs on Fly in `ord` and your Postgres runs on Fly in `ord`, they are talking over a private network inside the same facility. That is about as short as a query path gets. If your workload is chatty, that latency is worth more than the price difference, and moving the database out to any external host adds a hop you cannot optimize away.

**One vendor, one bill, one CLI.** There is real value in `fly deploy` and `fly mpg` being the same tool with the same auth. If your team is small and your operational surface is "everything is on Fly", splitting that is a genuine cost, not a free lunch.

**Included HA.** High availability comes with the plans. If you need it, you are getting something for the $38 that a $15 flat plan is not offering you, and comparing the two prices without saying that would be dishonest.

The case for moving is narrower and specific: you have more databases than production ones, they are mostly idle, things outside Fly need to reach them, or the second engine you need is not one Fly operates itself.

## FAQ

### How much does Fly Managed Postgres cost?

As of 2026-08-27, plans are Basic $38/month, Starter $72, Launch $282, Scale $962, and Performance $1,922, plus $0.28 per provisioned GB of storage per 30-day month up to 1 TB. Inter-region private network usage has been billed since February 2026. There is no hobby tier.

### Can I connect to Fly Managed Postgres from outside Fly?

Not directly. Fly's docs are explicit that an MPG cluster runs inside your private network and is not accessible over the public internet. `fly proxy` and `fly mpg connect` forward it to your own machine, and the official public path is the `fly-apps/fly-mpg-proxy` app, which ships allowing `0.0.0.0/0`. If you deploy that, tighten the allowlist first.

### What is the difference between the direct and pgbouncer hostnames?

`direct.<id>.flympg.net` connects straight to Postgres and bypasses the pooler. `pgbouncer.<id>.flympg.net` goes through PgBouncer. Use the direct hostname for `pg_dump`, migrations, and anything that expects session-level behavior; use the pooler for application traffic with lots of short connections.

### Is Redis on Fly the same product as Fly Postgres?

No. Redis on Fly is Upstash, a partner integration with its own account and pricing model. Worth knowing before you count Fly as a single-vendor stack.

### Do I have to move my app to move my database?

No. Dump from a machine on the private network or through the proxy, load into the new database, then `fly secrets set DATABASE_URL=...`, which triggers a redeploy. The app stays on Fly.

### Is $15/month actually comparable to $38/month?

Not feature for feature, and I am not going to claim it is. Fly's plans include high availability; a flat $15 Pro plan gives you up to 10 databases, 25 GB, every engine on our shared cloud, 30-day rolling backups, and no meter. Different shapes. If you need HA on one production database, Fly's number is buying you something. If you need six small databases and none of them need HA, the floor is the thing that decides it.

## The wrap-up

Fly built a Managed Postgres that reflects the platform's opinions: private by default, sized for production, priced per cluster. Every one of those is defensible in isolation. Together they mean the cheapest thing you can buy is $38 a month and it is not on the internet.

If your stack lives on Fly and your database serves that stack, stay. If your database count keeps growing, most of them are idle, and half the things that want to query it do not run on Fly, start at the [Fly.io migration page](/migrate/fly), or [create an empty Postgres](https://layerbase.com/create/postgresql) and see whether the tunnel was doing anything you miss.
