Open-source alternative to Fly.io Managed Postgres

Fly.io Managed Postgres can be replaced with PostgreSQL you run on your own servers, using Coolify or Dokku for small apps or CloudNativePG or Patroni where failover matters.

On this page

Open-source alternative to Fly.io Managed Postgres for small apps and HA clusters

If a Fly.io app's Managed Postgres plan and storage charges, or the location of its data, now prompt a move, the good news is that PostgreSQL is released under the PostgreSQL License, a permissive license similar to the BSD or MIT licenses, so you can run it on servers your team controls. For a small app, Coolify or Dokku can deploy PostgreSQL next to the application with scheduled backups to S3-compatible storage. For workloads that need automatic failover, CloudNativePG or Patroni on Kubernetes or VMs is the usual path, because PostgreSQL itself does not detect a failed primary or promote a standby.

The right choice depends on two things you should settle before touching production. The first is your recovery targets: how much data you can afford to lose, and how long the app can be down. Scheduled logical dumps to object storage give you point-in-time gaps measured in backup intervals, while a replicated cluster with continuous WAL archiving narrows that gap but adds moving parts. The second is in-house operating skill. Someone on your team must own upgrades, restores and failover drills, and PostgreSQL's own documentation on continuous archiving and point-in-time recovery describes the building blocks you will need to configure and test.

Before you commit, confirm which PostgreSQL major version you will run against the community support window in the PostgreSQL versioning policy, check that your current Fly.io database size and connection count fit a single server, and run a restore test on a copy of real data. Your recovery objectives and your team's capacity to run a cluster, not the license, decide whether a single Coolify or Dokku database or a CloudNativePG or Patroni cluster is the correct target.

Which Fly.io Postgres capabilities map to which open-source option

This table maps the Postgres capabilities teams usually rely on from Fly.io Managed Postgres to the open-source options that cover them. Read each row as the capability you need, then check which option covers it and where you must add tooling or confirm behavior yourself. Gaps are marked plainly so you can plan the operating work before you migrate.

CapabilityCoolify or Dokku with dokku-postgresCloudNativePG or Patroni
ProvisioningCoolify deploys PostgreSQL from its database catalog. The dokku-postgres plugin creates a service and links it to an app, setting DATABASE_URL.CloudNativePG and Patroni run PostgreSQL on Kubernetes or VMs you operate, so provisioning means cluster definitions and storage planning.
Scheduled backups to object storageCoolify runs pg_dump custom-format backups on cron to S3-compatible storage with retention. dokku-postgres runs one-off or scheduled backups to S3-compatible storage.Set up backups with your own tooling, such as pgBackRest or Barman, configured to your object store. Confirm the tool and its retention settings.
Point-in-time recoveryGap: scheduled logical dumps restore to the dump time, not to an arbitrary moment. Continuous WAL archiving is not provided by these tools.Possible with continuous archiving and WAL retention configured through your backup tooling. Confirm restore testing in your environment.
Read replicasNot provided as a managed feature. You would configure PostgreSQL hot standby replication manually on separate servers.Hot standby replicas are supported by PostgreSQL. CloudNativePG and Patroni manage replica creation and roles; confirm the read routing you need.
Automatic failoverGap: PostgreSQL does not detect primary failure or promote a standby on its own, and neither tool supplies failover on a single server.Patroni and CloudNativePG provide external failover management. Confirm promotion timeouts and fencing behavior with your team.
Connection poolingInstall PgBouncer alongside the database and point apps at it. This is a manual deployment step.PgBouncer runs as a separate deployment in front of the primary. Confirm pool modes that match your application's transaction handling.
Major version upgradesUse pg_dumpall with restore, pg_upgrade, or logical replication. Plan downtime for the dump and restore path.Logical replication can support a major upgrade with short downtime. Confirm the procedure against your cluster tooling before relying on it.
AuthenticationSet authentication through pg_hba.conf and the plugin defaults. Confirm the methods you need, such as SCRAM, certificates or LDAP, are configured.Authentication is set in PostgreSQL configuration and cluster manifests. Confirm TLS and certificate handling with your platform team.
MonitoringNot bundled as a full monitoring stack. Add exporters and dashboards, and confirm which metrics your alerts need.Operators expose cluster health through Kubernetes and PostgreSQL metrics. Confirm alerting for replication lag and failover events.

Which PostgreSQL option fits which workload

Coolify deploys PostgreSQL as a one-click database resource on a server it manages over SSH, and it can run scheduled backups to S3-compatible storage. This fits small applications where one server, a short recovery window and a single operator are acceptable, and where the team wants a web interface rather than shell work for routine tasks. The default setup runs on a single server, so the database shares that server's failure domain.

  • Backups: Scheduled PostgreSQL backups use the pg_dump custom format, can upload to S3-compatible storage, and apply retention by count, days or size.
  • Restore path: Import Backup accepts SQL dumps, custom archives, tar archives and all-database dumps, which helps when moving data in or out.
  • Operating burden: You still own server patching, disk growth, backup verification and restore drills, because Coolify does not run a standby.
  • Trade-off: Backups are point-in-time snapshots, so recovery point depends on the schedule, and there is no automatic failover.
  • Cost: Coolify's self-hosted edition is free, so the recurring cost is the server, storage and the time spent operating them.

Before relying on this option, confirm the backup schedule, retention settings and a tested restore on a separate server with your own recovery objectives.

How the PostgreSQL parts connect to the app

The connection path decides how much of the Fly.io Managed Postgres experience you rebuild. On a single server, the app containers and the database should sit on a private Docker network, with the database port closed to the public internet. Coolify and Dokku both place an app and its linked database on the same host, and Dokku sets the app's DATABASE_URL when you link a Postgres service, so the application code usually needs no change. If connection counts grow, PgBouncer can sit between the apps and PostgreSQL as a connection pooler. Confirm which pooling mode your ORM and migration tool support before you add it, because some session-level features behave differently behind a transaction pooler.

The high availability path adds a standby and a failover decision. PostgreSQL supports hot standbys that answer read-only queries, and it offers synchronous replication, where a commit waits for the standby, and asynchronous replication, where it does not. Synchronous replication protects committed data at the cost of write latency, so the choice belongs in a documented recovery objective, not a default setting. The critical point is that PostgreSQL does not detect a failed primary or notify the standby on its own. An external tool must make that decision and promote the standby. CloudNativePG or Patroni performs that role on Kubernetes or on VM fleets, and both need an operator to test failover, fencing and client reconnection before go-live.

Whichever path you choose, confirm the network and the failover behavior in writing with your team. Check which hostname the apps resolve after a promotion, whether connection strings point to a virtual address or a proxy, and how long clients wait before they retry. These details are what a Fly.io user typically never sees, and they are where a self-hosted setup most often fails in a drill.

Keeping Fly.io apps while the database moves

Moving a database rarely happens in one step, so teams usually choose between keeping Fly.io compute against a self-hosted database, moving app and data together, or running both during cutover. Each option trades latency, egress and network exposure differently, and the cards below set out the decisions and checks for each.

Keep Fly.io compute, point at self-hosted Postgres

Fly.io machines keep running while the connection string points at PostgreSQL on your own servers. This is the lowest-risk first step, but every query now crosses the network between Fly.io and your data center. Measure round-trip time from the app region to the database before committing, because chatty ORMs multiply even small delays. Confirm that the database host accepts traffic only from the Fly.io egress paths you intend to allow.

Use TLS for every cross-network connection

When the app and database sit on different networks, require TLS on the PostgreSQL server and verify the server certificate on the client side. PostgreSQL supports certificate-based client authentication, and SCRAM is the recommended password method, since MD5 password authentication is deprecated in PostgreSQL 18. Set hostssl rules in pg_hba.conf so plaintext connections are refused. Rotate the credentials stored as Fly.io secrets as part of the cutover plan.

Confirm Fly.io private networking first

Before choosing a topology, ask Fly.io which private networking options apply to your organization and region, and whether they reach hardware outside Fly.io. Private addresses between Fly.io apps do not reach a database in your own data center by default, so the route is likely to be public or through a tunnel you operate. Get written answers on address ranges, egress pricing for database traffic and any limits on outbound connections, because these determine the design.

Estimate egress and per-query latency

Traffic from Fly.io to your database leaves Fly.io's network, so ask how outbound bandwidth is billed for your plan and region. Egress often grows with result set size, not only with request count, so review the largest queries and any batch jobs. Latency matters more than bandwidth for transactional workloads: a page that issues dozens of sequential queries will feel every extra millisecond. Test with production-like query volumes rather than a single health check.

Move app and database together

Moving both the app and PostgreSQL to Coolify or Dokku on the same host or private network removes the cross-network hop entirely. It also means replacing Fly.io machines, volumes and regional placement in one project, which increases scope and the number of changes that can fail at once. Choose this path when the app is small, its data set is manageable, or you are already moving compute off Fly.io. Plan a rollback that can restore the database, since a Coolify rollback redeploys an application image but does not restore databases.

Run both during cutover

A cutover with both databases live uses logical replication from Fly.io Postgres to the new server, then switches the connection string once the two are in sync. PostgreSQL logical replication works between different major versions, which can help when the target runs a newer release, and it typically needs only seconds of write downtime at the switch. Confirm with Fly.io which Postgres version and replication settings your cluster exposes, and rehearse the switch with a staging copy before the production window.

Moving Fly.io Postgres data to your own PostgreSQL

This sequence moves a Fly.io Postgres database to PostgreSQL you run, with a verified dump, a tested restore and a cutover that you can roll back until the new backups are proven. It is built so the old database stays untouched until the new one has passed validation.

  1. Inventory versions, extensions and connections

    Record the exact PostgreSQL major and minor version on the Fly.io cluster, every installed extension, the database names, roles and the connection strings your apps read from DATABASE_URL and secrets. Confirm the target major version against the PostgreSQL versioning policy, since the support window for each release differs. Done when you have a written inventory that a second engineer has reviewed and that lists each app and environment variable pointing at the database.

  2. Choose the target and confirm extension support

    Decide where PostgreSQL will run: a Coolify database resource or a Dokku postgres plugin service on your own server, or a CloudNativePG or Patroni cluster if you need failover. Check that every extension from the inventory is available in the target image, because Fly.io images and self-hosted images may not ship the same packages. Done when each extension is confirmed present on the target, or you have a documented replacement.

  3. Take a consistent dump of the source

    Stop writes if your application allows it, then run pg_dump against the Fly.io database in custom format so the dump reflects one point in time. Keep the dump file, record its checksum and store a copy outside the Fly.io environment. Done when the dump completes without errors and a restore of it to a scratch instance returns the expected table counts.

  4. Restore into the target and rehearse

    Restore the dump into the new PostgreSQL instance, then run the same restore a second time on a fresh scratch database to confirm it is repeatable. Watch for role and ownership errors, which usually mean the inventoried roles were not created first. Done when the restore finishes cleanly, roles and extensions match the inventory, and the rehearsal produces the same row counts as the source.

  5. Validate the restored data and application behavior

    Compare row counts and checksums for the largest tables, run the application test suite against the restored database and check that sequences, indexes and constraints exist. Confirm that authentication works with the methods you configured, since PostgreSQL supports several client authentication options and MD5 password authentication is deprecated in favor of SCRAM. Done when the application passes its tests against the target and the comparisons match.

  6. Cut over or replicate with logical replication

    For a short write window, stop writes, take a final incremental dump, restore it and switch the connection string. If a longer cutover is unacceptable, set up logical replication from the Fly.io primary to the target, let it catch up and cut over during a brief pause. Logical replication also works across major versions, so it can serve as an upgrade path. Done when the application reads and writes against the target and replication lag, if used, has reached zero.

  7. Keep the source and prove backups before decommissioning

    Leave the Fly.io database running in read-only mode and keep it until scheduled backups on the new server have run, uploaded to S3-compatible storage and restored successfully at least once. Coolify's backups and Dokku's postgres plugin backups both need a tested restore before you rely on them. Done when a restore from the new backup has been verified and you have signed off on decommissioning the Fly.io database.

Questions teams ask before replacing Fly.io Managed Postgres

What are the cost components of running our own PostgreSQL instead of Fly.io Managed Postgres?

The cost is split between the servers or virtual machines that host the database, the storage and backup space, the network traffic used for backups and replicas, and the people who set up, patch and monitor it. Managed Postgres bills per plan and storage, so the managed bill is predictable per database. Self-hosting shifts that spend: infrastructure is billed by your provider, software licensing is zero because PostgreSQL uses the PostgreSQL License, and the largest recurring item is usually staff time. Ask any implementation partner for a quote that lists each component separately, including who pays for each and which items recur monthly versus one time.

How long does a migration off Fly.io Managed Postgres take?

Duration depends on database size, the number of applications connected to it, how much downtime the business accepts, and how many backup and failover requirements must be proven before cutover. A small app with one database and a tested dump-and-restore path is far simpler than a multi-application cluster with replicas. Logical replication can cut downtime for a major version change to several seconds according to the PostgreSQL upgrading documentation, but the setup and rehearsal still take time. Ask for a written timeline tied to a named scope, with rehearsal and rollback steps listed as deliverables.

What does our team have to operate after go-live?

After cutover, your team owns patching, monitoring, capacity planning, connection management, backup verification and restore testing, and security updates. PostgreSQL releases minor versions at least once every three months, and minor updates replace executables and require a restart, so someone must schedule them. Fly.io no longer carries that work, so the plan should name an owner, an on-call path and a runbook for each routine task before the first production load arrives.

Is a single server enough to replace Fly.io Managed Postgres?

A single server can be enough for a small application with modest data volume and a recovery plan that accepts restoring from backup after a failure. It is not a high availability design. PostgreSQL supports hot standby servers and synchronous or asynchronous replication, but it does not detect a failed primary or promote a standby on its own, so automatic failover needs external tools such as CloudNativePG or Patroni. Decide the acceptable outage window first, then choose between one server with tested backups and a replicated cluster.

How do backups and point-in-time recovery differ?

Scheduled logical backups save a snapshot of the database at a moment in time, so restoring them returns the data to that moment and loses everything written afterward. Point-in-time recovery uses a base backup plus archived write-ahead log files to replay changes up to a chosen second, which reduces data loss but needs more configuration and storage. Coolify can schedule pg_dump backups to S3-compatible storage, and the dokku-postgres plugin supports S3-compatible backups too. Neither gives continuous archiving on its own, so confirm whether your recovery target requires PostgreSQL's continuous archiving documentation approach.

Which PostgreSQL version should we choose, and when does support end?

Choose a version that is still supported for the whole life of the system you are building. PostgreSQL 18 was first released on September 25, 2025, and is supported until November 14, 2030. PostgreSQL 17 is supported until November 8, 2029, version 16 until November 9, 2028, version 15 until November 11, 2027, and version 14 until November 12, 2026. Versions 13 and earlier are no longer supported. A version that ends support soon will need a major upgrade, so plan that upgrade into your timeline rather than treating it as a later surprise.

When should we hire outside help for this migration?

Bring in outside help when the database carries regulated data, when recovery targets must be proven rather than assumed, or when the team lacks in-house PostgreSQL operations experience. DeployOpen plans, implements, hardens, backs up, documents and supports self-hosted platforms inside your own infrastructure, and most engagements are fixed scope with deliverables and timelines agreed in writing before work starts. DeployOpen does not issue audit reports or certifications, so independent auditors remain responsible for any assessment. Ask for a written scope that names the backup, restore and failover tests you will receive.

Operating risks the team takes on

Running PostgreSQL yourself moves several operational duties from the platform vendor to your team. The cards below cover the duties that most often decide whether a self-hosted database holds up, and each one needs an owner, a schedule and a record of the last time it was tested.

Backup testing and restore drills

A scheduled backup only protects you if a restore works. Coolify's PostgreSQL backups use the pg_dump custom format and can be uploaded to S3-compatible storage with retention by count, days or size, but a backup job that reports success does not prove the dump is complete or restorable. Schedule restores into a separate server, time them, and check row counts on critical tables. Also confirm that Coolify's rollback guidance does not restore databases, so data recovery depends entirely on your backup set.

Minor and major upgrades

Minor releases keep the same storage format, so the work is replacing executables and restarting. Major upgrades need a planned method: pg_dumpall with restore, pg_upgrade, or logical replication, which the PostgreSQL project says can limit downtime to several seconds. Your PostgreSQL 14 installation reaches end of support on November 12, 2026, so an upgrade calendar is a near-term item. Confirm which PostgreSQL version your Dokku or Coolify template pins before you plan.

Monitoring and alerting

Managed Postgres usually includes health dashboards and paging by default. Self-hosted, you decide which signals matter: replication lag if you run standbys, disk growth on the data volume, connection counts, failed backup jobs and certificate expiry for TLS. Alerts on backup job failures are the cheapest check, because a silent failure stays hidden until a restore is needed. Ask your team which alert reaches a person at night and who acts on it.

Security patching and authentication

You patch the operating system, Docker runtime, proxy and PostgreSQL image yourself. In authentication, set password_encryption to scram-sha-256 and retire MD5 password entries, since PostgreSQL 18 deprecated MD5 in favor of SCRAM. Review pg_hba.conf so only the application network and admin hosts can connect, and restrict superuser access. Confirm that your Coolify or Dokku database template does not expose the port publicly.

Capacity planning

Storage, memory and connection limits are set by the server you choose, and nothing scales them for you. Track database size growth against the free disk on the host, because Coolify's minimum requirements apply to the platform, not to your data. Plan connection pooling with PgBouncer before the app layer exhausts connections. Ask your provider what happens to backups and data when the volume fills.

How DeployOpen scopes and delivers a PostgreSQL replacement

DeployOpen plans, implements, hardens, backs up, documents and supports self-hosted open-source platforms inside your own infrastructure. For a move off Fly.io Managed Postgres, we start with a written scope that names your databases, recovery targets and the backup destination before any server is touched.

How we scope

  • Inventory every Postgres database, its major version, extensions, connection counts and data volume before choosing a target.
  • Agree in writing whether the target is a Coolify or Dokku database, a CloudNativePG cluster, or a Patroni setup, and why.
  • Define the recovery point and recovery time you need, and who owns failover decisions, before any work starts.

How we build

  • Deploy PostgreSQL on servers or Kubernetes nodes you control, with the S3-compatible backup target and retention set in configuration.
  • Configure authentication with SCRAM rather than MD5, restrict network access, and set TLS for client connections.
  • Test a full restore into a separate environment and record the measured time, so the figures in the runbook come from your own run.

How we hand over

  • Deliver a runbook covering connection strings, backup schedules, restore steps, and the cutover sequence from Fly.io.
  • Document the logical replication or dump-and-restore path used for the move, with rollback steps if cutover fails.
  • Hand over configuration, credentials ownership and a list of items your team must confirm with the vendor or your own environment.

How we support

  • Ongoing support, upgrades and continuous testing are available as a retainer after handover.
  • A retainer can cover minor version updates and planned major upgrades, scheduled against the PostgreSQL support dates you choose.
  • Quotes follow from the written scope, so ask for the scope, deliverables and timeline to be listed separately in the proposal.

Sources and further reading

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.