Guide

Leaving Fly.io After the Free Tier: Secrets, Volumes, and the Dockerfile You Already Have

SnapDeploy Team 2026-11-04 Updated 2026-11-04 8 min read
flyiomigrationdockerpostgresqlfree-tier

Fly.io's free allowance is gone: new organisations get a trial of two hours of compute or seven days, whichever ends first, and then everything is pay-as-you-go. That is not a scandal, Fly's smallest machine is about $2 a month, but it changes who Fly is for. This guide is for people whose side project is on Fly and who would rather it cost nothing while idle. It is short on drama and long on the specific things that differ: secrets you cannot export, volumes you cannot bring, and a region model you will not miss.

Fly's pricing, in the numbers that matter

  • Trial: 2 hours of compute or 7 days. Then pay-as-you-go with no minimum.
  • Smallest machine (shared-cpu-1x, 256 MB): about $2.02 a month if it runs all month; billed per second, so a stopped machine costs nothing for compute.
  • Volumes $0.15 per GB-month of provisioned size, billed whether or not the machine is running; a dedicated IPv4 is $2 a month; outbound bandwidth from $0.02 per GB.
  • Machines can auto-stop when idle and auto-start on a request, which is Fly's version of sleeping.

Stay on Fly if you use what it is good at: multiple regions, machines you control at the API level, or a workload that needs more than 512 MB and a quarter of a CPU. A $2 to $5 monthly bill for that is fair. Move if the app is a single small service you visit occasionally and you would like the idle bill to be zero.

What maps to what

On Fly On a container host (SnapDeploy)
Dockerfile (most Fly apps already have one)The same Dockerfile, unchanged; the port is read from EXPOSE
[http_service] internal_portEXPOSE in the Dockerfile, or the container's port setting; read PORT in the app to be safe
auto_stop_machines / auto_start_machinesBuilt in on the free tier: sleep after 15 minutes without traffic, wake in about a minute with a wake page; Always-On ($12/month) never sleeps
[env] block in fly.tomlEnvironment variables in the container settings
fly secretsAlso environment variables; see below, they cannot be read back from Fly
[mounts] volumesNo volumes on containers; use a managed database add-on or object storage
Fly Postgres / Managed PostgresPostgreSQL Mini ($29/month), a $1 DB Sprint Pack for 12 hours, or a free external Postgres such as Neon
Regions, private networking (6PN), machines APIOne region; containers talk over public HTTPS URLs; no equivalent to the machines API
Custom domain with a Fly certificateAlways-On only; free containers live on containers.snapdeploy.app

Step 1: the Dockerfile is probably done

Fly deploys from a Dockerfile when the repository has one, and fly launch writes one for common frameworks, so most apps arrive with a working file. Check three things: the app listens on 0.0.0.0 and on PORT (Fly apps often hard-code the internal_port); nothing in the image depends on a mounted volume path such as /data; and there is no fly.toml-only behaviour the app expects, like a release command. A release command becomes the first part of the container's CMD (for example alembic upgrade head && …).

Step 2: secrets, the one-way door

Fly secrets are write-only: fly secrets list shows names and digests, never values. If you did not keep the values elsewhere, you have two options: read them from inside a running machine (fly ssh console, then printenv), or rotate them at the source (a new API key from the provider) and set the new value on both platforms during the cut-over. Rotating is usually the better answer; it also means the old platform holds nothing valid once you leave. Plain [env] values are in fly.toml and copy straight across.

Step 3: the database

Fly Postgres is reachable from your machine through a proxy, which is enough for a dump:

fly proxy 15432:5432 -a my-db-app          # in one terminal
pg_dump --no-owner --no-privileges "postgres://postgres:PASSWORD@localhost:15432/app" > backup.sql
psql "$NEW_DATABASE_URL" < backup.sql

Run the app against the new database for a day before deleting the Fly database and its volume; the volume is what keeps billing if you forget it.

Step 4: volumes, if you have one

This is the only step with real work. A volume on Fly usually holds one of three things: a SQLite database (move it to Postgres, or accept that the container version is disposable), uploaded files (copy them to an S3-compatible bucket with fly ssh sftp to pull them out, then point the app at the bucket), or a cache (delete it). Container filesystems on SnapDeploy are ephemeral by design; the managed databases have persistent storage, the containers do not.

Step 5: deploy and cut over

  1. Push the repository. Containers → Deploy from GitHub → pick it; add the environment variables and secrets; attach or paste the database.
  2. Deploy (a few minutes), test on the containers.snapdeploy.app URL, then wait 20 idle minutes and load it once more to see the wake page and confirm the app comes back cleanly.
  3. If the app had a custom domain on Fly, either take Always-On and point the domain's A record at the address in the container's domain settings, or keep the domain on Fly a little longer.
  4. Scale the Fly app to zero machines (fly scale count 0) for a week before destroying it. Stopped machines cost nothing for compute; only the volume and any dedicated IPv4 keep billing.

Test the image locally first

docker build -t app .
docker run --rm -p 8080:8080 -e PORT=8080 --env-file .env.local app
curl -i http://localhost:8080/

If it needs a path from [mounts] to exist, you will see it here: the app crashes on start looking for /data. Fix that before the first deploy.

Where free stops on the other side

  • 4 containers, 512 MB and 0.25 vCPU each, 100 container-hours a month counted while awake. Fly's 256 MB machine is smaller but always yours.
  • Sleep after 15 minutes without traffic, about a minute to wake. Fly's auto-stop is configurable; ours is not.
  • No volumes, one region, no private network between containers, custom domains only on Always-On.

Sources: Fly.io pricing and billing pages as of September 2026 (trial, machine, volume and bandwidth prices); SnapDeploy numbers from the free tier docs and add-on pricing.

Ready to Deploy?

Deploy free. 10 deploys a day, 100 hours a month, no credit card.

Run this yourself: Get a dedicated NVIDIA T4 (16 GB) for a flat $499/mo or A10G (24 GB) for $999/mo — never shared, never spot, no hourly metering. See dedicated GPU hosting →

One-click Ollama, vLLM, ComfyUI, Whisper, PyTorch & more — or deploy your own GitHub repo or Docker image. Compare plans.

FIRST OF ITS KIND

Sprint Pack — ₹99 for 24 hours

The first managed container PaaS to offer a one-time 24-hour Always-On pass under $5. Unlimited deploys + Always-On for one Small (512 MB) container — including WebSockets & real-time apps. No subscription, no auto-renewal. Stack two for 48 hours.

Need a managed database too? DB Sprint Pack — ₹99 / 12h for Postgres, MySQL, MariaDB, Mongo, Redis, or RabbitMQ.

Tip: Need 24 hours of Always-On for a demo, weekend, or quick test — or WebSockets & real-time apps? Sprint Pack is ₹99 one-time — no subscription, no auto-renewal.

Need a managed Postgres / MySQL / Mongo / Redis instead? DB Sprint Pack — ₹99 / 12h.

Take SnapDeploy with you

Deploy, monitor and wake your containers from your iPhone.

Download on the App Store

Get DevOps Tips & Updates

Container deployment guides, platform updates, and DevOps best practices. No spam.

Unsubscribe anytime. We respect your privacy.

More Articles