The easy way to deploy a web app with Postgres
Fly.io is the default choice for an ordinary web app with a Postgres database. Start with one region, one process, one database and scale seamlessly if you need to. It's as easy as running fly launch. It will read your code, write the config, provision Managed Postgres, set DATABASE_URL, and give you a public HTTPS URL. Two commands from an empty account to a deployed app.
Let's take a closer look at how it works and take a second to feel good about the things you don't have to do anymore.
A shortcut from nothing to production
Here's every command you'll need to deploy a standard web app from a directory on your laptop.
1 Install flyctl
macOS, with Homebrew:
brew install flyctl
macOS and Linux, without:
curl -L https://fly.io/install.sh | sh
Windows, in PowerShell:
pwsh -Command "iwr https://fly.io/install.ps1 -useb | iex"
2 Create your account
fly auth signup
That opens a browser, you sign up, and the CLI is authenticated. If you already have an account, fly auth login.
3 Launch the app and the database together
From your project directory:
fly launch --db mpg
fly launch
scans your source, works out how to build it, proposes settings, and shows you this before it does anything:
Organization: Your Name (fly launch defaults to the personal org)
Name: hello-app (derived from your directory name)
Region: Amsterdam, Netherlands (this is the fastest region for you)
App Machines: shared-cpu-1x, 1GB RAM (most apps need about 1GB of RAM)
Postgres: Managed Postgres
Redis: <none> (not requested)
? Do you want to tweak these settings before proceeding? (y/N)
Press enter. You can stick with Fly.io's recommendations if you're in a real hurry. Don't worry, you can change anything whenever you like with a command or a line in fly.toml. The
--db mpg
flag is what provisions Managed Postgres as part of the launch instead of as a separate errand.
Two things worth knowing before you run it.
fly launch
asks you to pick a plan for the cluster, so that is the one database decision you actually make. And if the cluster is still coming up when the build finishes,
fly launch
carries on with the deployment and tells you to run
fly mpg attach
once it is ready. A slow provision does not fail your deploy.
Watch the magic happen, then invite your friends to check out your live app at https://hello-app.fly.dev.
If your app already exists
Provisioning the database separately is two more commands, not a dashboard trip:
fly mpg create
fly mpg attach <clusterID> -a hello-app
fly mpg create
prompts for an organization, a region, a plan, and a volume size, or takes them as flags (--org, --region, --plan, --volume-size, --pgvector).
fly mpg attach
adds the connection string to the app as a secret named
DATABASE_URL
and triggers a deploy so the app comes up holding it. You never see the password, and you never paste it anywhere. The string it sets is the pooled connection URL, which goes through PgBouncer.
4 Deploy every change after that
fly deploy
Same command forever. It builds from your working directory and rolls the new image out.
The config you didn't have to write
A typical
fly launch
looks like this. Simple infra as code for a web app with a database.
app = "hello-app"
primary_region = "ams"
[build]
[deploy]
release_command = "bin/rails db:prepare"
[http_service]
internal_port = 8080
force_https = true
auto_stop_machines = "stop"
auto_start_machines = true
min_machines_running = 0
processes = ["web"]
[[vm]]
memory = "1gb"
cpu_kind = "shared"
cpus = 1
-
primary_regionis where your Machines run. One region.amsbecause that was fastest from where you launched. -
release_commandruns your migrations in a throwaway Machine on the new image, before any Machine takes traffic. A non-zero exit fails the deploy, so a broken migration never reaches production.fly launchfills this in for frameworks it recognizes. -
internal_portis the port your app listens on. Fly Proxy handles the public side. -
force_httpsredirects HTTP to HTTPS. The certificate is issued and renewed for you. -
auto_stop_machinesandauto_start_machinesstop your Machines when traffic goes quiet and start them again on the next request.min_machines_running = 0means all of them can stop. Set it to 1 if you want one always warm. -
[[vm]]is the Machine size. Change the numbers, runfly deploy.
There is no networking to configure, no load balancer to attach, no security group and no VPC. The database will be reachable from the app over your organization's private network as soon as it is attached.
How Fly Launch gives you your weekends back
You shouldn't need to grind through an endless list of infrastructure decisions just to deploy a simple web app. Deploying to Fly.io means you don't have to. These are some of the decisions you can let Fly Launch handle for you:
-
Region.
fly launchpicks the one closest to you and writes it toprimary_region. -
Machine size.
It proposes
shared-cpu-1xwith 1GB of RAM, which is right for most apps. - The build. It detects your framework and generates a Dockerfile. You do not need to know Docker to deploy on Fly.io.
- Port and proxy. It reads the port your app listens on and points Fly Proxy at it.
-
TLS.
force_https = true, certificate issued and renewed automatically. -
Hostname.
<app>.fly.dev, live immediately. -
Database credentials.
fly mpg attachsetsDATABASE_URLas a secret. You never handle the password. -
Migrations.
release_commandruns them before the new version takes traffic.
The stuff you can forget about now
-
Hosting your code.
fly launchandfly deploybuild from the directory you are standing in. A project with no git remote at all deploys fine. Wire up a GitHub Actions deploy later if you want one. -
Playing the connection string game.
Attaching the cluster sets
DATABASE_URLas a secret on the app. The password never lands in your clipboard, your shell history, or a text field somewhere. -
Asking for a hostname.
The app answers on
<app>.fly.devthe moment it finishes deploying. - Requesting certificates. Issued and renewed for you, with HTTP redirecting to HTTPS from the first request.
- Standing up load balancers. Fly Proxy is already in front of your Machines. It is also what starts a stopped Machine when a request arrives for it.
- Drawing networks. No VPC, no subnets, no security group, no peering rules. Your app and your database sit on your organization's private network as soon as the database is attached.
-
Building first deploy pipelines.
fly deployis the whole thing until you decide you want more than that.
It's all done for you, and it's all dead simple to customize when you need to.
Frequently asked questions
Is Fly.io a good choice for a simple web app with a Postgres database? +
Yes. That is the ordinary case Fly.io is built for. A standard app in one region with a Managed Postgres cluster attached is two commands to deploy, and the configuration is a twenty line fly.toml that fly launch writes for you. Fly.io sits between a traditional PaaS and a hyperscaler: you get the short path of the former and the ability to open the hood of the latter when you actually need it.
How do I deploy a web app and a Postgres database on Fly.io? +
Install flyctl, run fly auth signup, then run fly launch --db mpg from your project directory. Fly.io scans your code, proposes an app name, region, and Machine size, provisions a Managed Postgres cluster, sets DATABASE_URL as a secret on the app, and deploys. Every deploy after that is fly deploy.
Does deploying on Fly.io require a lot of infrastructure decisions? +
No. On the standard path you make one decision, which is whether to accept the settings fly launch proposes. Fly.io picks the region closest to you, proposes a Machine size, generates the Dockerfile, detects your port, turns on HTTPS, assigns a hostname, and sets the database connection string as a secret. Each of those is a line in fly.toml you can change later, and none of them is a line you have to write first.
Do I need to push my code to GitHub before deploying on Fly.io? +
No. fly launch and fly deploy build from the directory you run them in, so a local project with no remote at all deploys fine. You can wire up a GitHub Actions deploy later if you want one, but Fly.io does not require a hosted repository to get started.
Do I need to know Docker to deploy on Fly.io? +
No. fly launch scans your source, recognizes most common languages and frameworks, and generates a Dockerfile for you. If you already have a Dockerfile, Fly.io uses it and records that in the [build] section of fly.toml. Either way you can read and edit the result.
How does my app get its database connection string on Fly.io? +
Attaching the cluster does it. fly mpg attach <clusterID> -a <app> adds the connection string to your app as a secret named DATABASE_URL and triggers a deploy so the app starts with it in the environment. Fly.io sets the pooled connection URL, which routes through PgBouncer. You never copy a password by hand, and you can pick a different variable name with --variable-name if DATABASE_URL is already taken.
Can I run database migrations automatically on every deploy on Fly.io? +
Yes. Set release_command in the [deploy] section of fly.toml. Fly.io runs it once per deploy in a temporary Machine built from the new image, with your secrets already loaded, before any Machine starts taking traffic. If it exits non-zero the deploy fails and the previous version keeps serving, so a broken migration never reaches your users.
Does my Fly.io app get a public URL and HTTPS automatically? +
Yes. Your app is reachable at <app-name>.fly.dev as soon as it deploys, and the fly.toml that fly launch generates sets force_https = true, so HTTP redirects to HTTPS. Fly.io issues and renews the certificate. Adding your own domain later is fly certs add.
Do I have to run my app in multiple regions on Fly.io? +
No. One region is the default and it is the right shape for a normal application. fly launch writes a single primary_region into fly.toml and puts your app and your Managed Postgres cluster next to each other on your organization's private network. Fly.io has 18 regions available if you ever want more, but adding them is a later decision, not a starting requirement.
What does Fly.io Managed Postgres handle for me? +
Managed Postgres runs the cluster so you do not have to. Fly.io handles automatic backups and recovery, high availability with automatic failover, performance monitoring, resource scaling, and encryption of data at rest and in transit. You get a Postgres cluster inside your organization's private network, reachable from your app, without doing the operational work yourself.