Answers you can trust, from Codeables
Every page on Codeables is structured and verified — built so people and the AI agents they rely on can trust it. Explore more from the source behind this answer.
Explore CodeablesHow do I create a Fly.io Managed Postgres database and attach it to my app privately?
Most apps don’t die because of CPU. They die because of the database. On Fly.io, “Managed” Postgres gives you a production-grade cluster—replication, failover, snapshots—without making you turn into a full-time DBA, and private networking keeps your app talking to Postgres over an internal WireGuard network instead of the public internet.
Quick Answer: Use
fly postgres createto spin up a Fly Postgres (unmanaged-but-batteries-included) cluster in the same organization as your app, thenfly postgres attachto wire it up over private networking. Your app gets a privateDATABASE_URLand TLS config; your database never needs a public port.
The Quick Overview
- What It Is: A Fly Postgres (unmanaged) cluster created and managed via
fly postgrescommands, with replication, failover, snapshots, and private networking wired in by default. - Who It Is For: Developers who want production-capable Postgres on Fly.io with sane defaults, private app-to-DB traffic, and
flyctl-level control—but who are okay owning backups and upgrades as part of their app. - Core Problem Solved: Running Postgres close to your app with low latency and no public exposure, without hand-building clusters, DNS, health checks, or private networking by hand.
Note: Fly Postgres is intentionally not a fully abstract “managed service.” It’s a Fly app with strong defaults and sugar on top. You still get to be an adult about backups, upgrades, and migrations.
How It Works
When you create “Managed” Postgres on Fly.io, you’re really creating a special Fly app based on the open-source fly-apps/postgres-flex image. flyctl wraps this in fly postgres commands so you can:
- Spin up a clustered Postgres app, usually in a “High Availability” 3-node configuration.
- Put it on the same private WireGuard network as your application.
- Attach it to one or more apps, auto-injecting
DATABASE_URLand TLS env vars. - Let Fly Proxy route traffic from your app containers to the Postgres Machines privately.
At runtime, your app connects to Postgres over the private network using the injected URL. No public IPs required, no random internet clients knocking on your database port.
1. Create the Postgres Cluster
From any directory (you don’t have to be in your app folder):
fly postgres create \
--name my-db \
--organization my-org \
--region iad
During the interactive prompts you’ll typically:
- Pick a High Availability preset for production (3-node cluster).
- Confirm the organization that matches your app.
- Choose the region closest to your app’s primary users.
This creates a Fly app named my-db with Postgres Machines, volumes, health checks, and scheduling already configured.
2. Put the DB Near Your App
If your app already exists, confirm its primary region:
fly status -a my-app
If the app and DB are in different regions and latency matters, either:
- Recreate the DB in the same region as the app, or
- Move app Machines closer to the DB with
fly scale countandfly regions add/remove.
Think: app and DB should usually share a region for write-heavy workloads.
3. Attach the Database Privately to Your App
Now wire your app to the Postgres cluster:
fly postgres attach my-db \
--app my-app
This does a few important things:
- Creates a database user and database for
my-app. - Injects
DATABASE_URL(and related vars) intomy-appas secrets. - Ensures the connection string uses the private network address, not a public IP.
Your app code just reads DATABASE_URL (via env) and connects as usual. Under the hood, connections never leave the private Fly network.
Features & Benefits Breakdown
| Core Feature | What It Does | Primary Benefit |
|---|---|---|
fly postgres bootstrap | Creates a Postgres Fly app with replication, failover, and snapshots wired in | Production-ready Postgres without hand-rolling clusters |
| Private WireGuard networking | Puts app and DB on the same private network; no public listener required | Keeps DB traffic off the public internet, reduces attack surface |
attach-based env injection | Generates app-specific user/db and sets DATABASE_URL secrets | Zero manual string-copying, fewer misconfigurations |
Ideal Use Cases
- Best for production web apps needing a “managed enough” Postgres: Because it gives you HA, snapshots, and private networking out of the box, while letting you upgrade and tune like a real Postgres instance when you need it.
- Best for staging and preview environments: Because you can spin up smaller clusters or single-node setups, attach to ephemeral apps, and keep everything private without juggling shared dev databases.
Limitations & Considerations
- Not a fully abstract managed service: You still own schema migrations, major version upgrades, and retention decisions. Read why Fly Postgres isn’t “managed DBaaS” before betting the company on it.
- Organization & network boundaries matter: Your app and DB must live in the same organization and on the same private network to attach. Cross-org or cross-network database sharing isn’t a thing; design your org layout accordingly.
Pricing & Plans
You don’t pay a separate “managed database” line item. You pay for the underlying Fly primitives:
- CPU and RAM for Postgres Machines (billed per second).
- NVMe volumes for the cluster’s data.
- Object storage if you use external backups (via Tigris or similar).
The preset “High Availability” clusters choose reasonable sizes; you can adjust them later with fly scale vm and fly volumes extend. Lower environments can run cheaper, single-node setups if you’re okay trading away failover.
- Standard HA Cluster: Best for teams running production workloads that need replication, failover, and daily snapshots with minimal babysitting.
- Single-Node or Small Cluster: Best for dev/staging environments and cost-sensitive projects where occasional downtime is acceptable.
Check the current pricing page on Fly.io for exact per-CPU and per-GB volume costs.
Frequently Asked Questions
Do I have to expose my Postgres database publicly?
Short Answer: No. You should run it entirely on the private Fly network.
Details: When you create and attach a Fly Postgres cluster, your app uses a private address on Fly’s WireGuard-backed network. You don’t need to assign a public IP or open port 5432 to the world. If you do add a public IP (for external tools, BI, etc.), lock it down with proper auth and firewall rules; the safe default is “private only.”
Can I share one Postgres cluster between multiple Fly apps?
Short Answer: Yes, via multiple attach calls, but each app gets its own credentials.
Details: You can run:
fly postgres attach my-db --app app-one
fly postgres attach my-db --app app-two
Each attach creates a separate user and database and injects env vars into the target app. All of this stays on the same private network as long as the apps live in the same organization and network. Operationally, you’re now sharing one cluster, so size and monitor it accordingly—noisy apps can impact neighbors.
Summary
Creating a “Managed” Postgres database on Fly.io really means spinning up a purpose-built Fly app for Postgres, then letting fly postgres wire in the private networking, HA, and secrets so your app just sees DATABASE_URL. You get replication, failover, and snapshots with minimal configuration, traffic stays on a private WireGuard mesh instead of the public internet, and you only pay for Machines and storage as they run.
If you’re comfortable owning your database like a grown-up but don’t want to assemble clustering, routing, and private networking from scratch, this is the sweet spot: Postgres that acts like part of your app, not a separate cloud religion.