Fly.io’s PostgreSQL offering is a managed database-as-a-service that runs your PostgreSQL instances as Docker containers on their global network.

Here’s a look at how it works in practice. Let’s say you want to set up a new PostgreSQL cluster for your application. You’d start by defining your database in your fly.toml file:

[services.postgres]
  image = "flyio/postgres:14"
  disable_proxy = true
  internal_port = 5432
  restart_policy = "fail"

[[services.postgres.processes]]
  name = "postgres"
  command = "bin/fly-postgres"

[[services.postgres.env]]
  PG_PORT = "5432"
  PG_USER = "fly"
  PG_PASSWORD = "$PG_PASSWORD" # Using a Fly.io secrets
  PG_DATABASE = "myapp_db"

Then, you’d create the secrets for your database user and password:

fly secrets set PG_PASSWORD="your_super_secret_password" --app my-postgres-app

And deploy it:

fly deploy --app my-postgres-app

Once deployed, Fly.io handles the orchestration, scaling, and patching of your PostgreSQL instances. You can connect to your database from your other Fly.io applications by referencing the database’s internal hostname. For example, if your PostgreSQL app is named my-postgres-app, your application can connect using the connection string: postgres://fly:your_super_secret_password@my-postgres-app.internal:5432/myapp_db.

Fly.io’s PostgreSQL is built on top of their global Anycast network, which means your database can be deployed across multiple regions. This provides high availability and low latency for your users worldwide. When you set up a new PostgreSQL cluster, Fly.io automatically creates a primary and at least one replica in different regions for redundancy.

The core problem Fly.io’s PostgreSQL solves is abstracting away the complexities of managing a distributed, highly available database. Instead of provisioning servers, configuring replication, setting up monitoring, and handling backups yourself, Fly.io provides these features out-of-the-box. You focus on your application code, and Fly.io takes care of the database infrastructure.

The internal bin/fly-postgres command is a crucial part of the Fly.io PostgreSQL image. It’s a wrapper script that initializes the PostgreSQL instance, sets up replication, and manages the database lifecycle according to Fly.io’s orchestration. It reads environment variables like PG_USER, PG_PASSWORD, and PG_DATABASE to configure the PostgreSQL server upon startup.

A common point of confusion is how replication and failover actually work. Fly.io uses pg_auto_failover under the hood. When the primary instance becomes unhealthy, pg_auto_failover automatically promotes a replica to become the new primary. This process is managed by the bin/fly-postgres script, which ensures that the cluster state is maintained and that your applications can reconnect to the new primary with minimal interruption. The restart_policy = "fail" in the fly.toml ensures that if the PostgreSQL process itself crashes unexpectedly, the Fly.io agent will attempt to restart it, which is essential for maintaining database availability.

The disable_proxy = true setting for the PostgreSQL service is important. It means that the Fly.io proxy won’t sit in front of your database. This is generally recommended for databases because database protocols are typically sensitive to proxying, and direct connections offer better performance and reliability. Your application connects directly to the PostgreSQL instance’s internal port.

The most surprising true thing about Fly.io’s PostgreSQL is that it’s not just a single PostgreSQL instance. Even a single-region deployment typically involves a primary and a replica, orchestrated to provide resilience. When you scale up to multiple regions, Fly.io sets up streaming replication between these geographically distributed instances, turning them into a single logical cluster accessible via the same internal hostname. This distributed nature is key to their high availability promise.

You’ll next want to explore how to manage database schema changes and migrations in a deployed Fly.io PostgreSQL environment.

Want structured learning?

Take the full Fly-io course →