Skip to main content

Fly.io's $0.08/GB Snapshot Bill: The Backup Line Item Your Self-Hosting Math Forgot

9 min readDora NodaDora Noda
Share
On this page

On January 1, 2026, backups on Fly.io stopped being free. Volume snapshots — the automatic daily copies Fly takes of every persistent volume — started billing at $0.08 per GB per month, with the first charges landing on February invoices. Most tenants barely noticed: Fly reported that 98% of customers would see no additional charges at all.

But "free for most" is not the same as "free," and this particular line item deserves a closer look than the announcement got. Snapshot billing is the quietest kind of hosted-platform cost: it is on by default, it scales with your data rather than your traffic, and it grows the invoice of a tenant who never asked for backups. If you are weighing hosted against self-hosted — or auditing a Fly bill that crept upward this year — the backup dimension belongs in the spreadsheet. Here is the line-item math.

The change, in one box​

Fly announced the change in October 2025 with admirably clear terms. Five numbers tell the whole story:

  • Price: $0.08/GB per month of stored snapshot data, first 10 GB free each month.
  • Metered on stored size, not provisioned size: if you have written 1 GB to a 10 GB volume, the snapshot stores roughly 1 GB. You pay for data, not empty capacity.
  • Incremental: only changes since the previous snapshot consume additional storage. When the oldest snapshot in the chain expires, some of its data rolls into the next one.
  • Automatic daily snapshots on every volume by default, with 5-day retention out of the box. Retention is configurable from 1 to 60 days, and you can disable automatic snapshots entirely per volume.
  • Snapshots cannot be manually deleted. They expire on their retention schedule, and that is the only way they go away.

Two adjacent facts complete the storage picture. Volumes themselves cost $0.15/GB per month of provisioned capacity — billed even when the volume is detached or attached to a stopped Machine. And a stopped Machine's root filesystem is billed at the same $0.15/GB rate: stopped is cheaper, not free.

The line-item math for a typical web-plus-Postgres stack​

Take the most ordinary production setup imaginable: a web app with a 10 GB volume holding about 3 GB of uploads and state, plus a Postgres database on a 40 GB volume holding about 25 GB of data. Default settings everywhere — daily snapshots, 5-day retention.

On Fly.io, the storage dimension breaks down like this:

Line itemMathMonthly cost
Volumes (provisioned)50 GB × $0.15$7.50
Snapshots (stored, minus free tier)~28 GB stored − 10 GB free = 18 GB × $0.08~$1.44
Storage total~$8.94

The snapshot line is about 16% of the storage bill here — real money, but not the headline. That ratio is exactly why the charge slipped past most teams: one extra dollar forty-four on an invoice dominated by compute.

On owned Hetzner disks, the same retention looks like this. Hetzner Cloud volumes run about €0.044/GB per month in EU regions, and volume snapshots about €0.011/GB:

Line itemMathMonthly cost
Volumes (provisioned)50 GB × €0.044€2.20
Snapshots (equivalent stored)~28 GB × €0.011~€0.31
Storage total€2.51 ($2.70)

The delta is roughly 3.3× on the storage dimension: ~$8.94 hosted versus ~$2.70 self-hosted for identical capacity and retention. In absolute terms that is about six dollars a month — nobody migrates a database over six dollars. But watch what happens as the data grows, because the two sides of this comparison scale very differently.

What moves the number: size, churn, retention​

Three variables control the snapshot line, and the defaults put two of them on autopilot. Stored data grows with your database; retention multiplies how many incrementals you keep; churn — how much of the data changes each day — determines how fat each incremental is. Fly's free 10 GB absorbs the small end entirely, which is why 98% of customers saw nothing. Past that threshold, the bill is linear in all three.

The table below models monthly snapshot cost (after the free tier) at a typical ~2% daily churn for a small Postgres, across stored-data sizes and retention settings:

Stored data5-day retention (default)30-day retention60-day retention
10 GB~$0.06~$0.46~$0.94
30 GB~$1.79~$2.99~$4.43
100 GB~$7.84~$11.84~$16.64

Three things stand out:

  • The free tier plus defaults genuinely cover the small-stack case. A 10 GB database at default retention costs six cents a month.
  • Retention is a quiet multiplier. Bumping a 100 GB database from 5 to 60 days more than doubles the snapshot line, and nothing in the dashboard forces you to confront that tradeoff when you raise it for compliance reasons.
  • Churn is the hidden variable. A write-heavy workload — event ingestion, append-only logs, a busy queue table — fattens every incremental in the chain, so two databases with identical sizes can carry very different snapshot bills.

The honest framing: snapshot billing punishes exactly the workload shape that also punishes every other usage-billed dimension — big, busy, and long-retained. If your database is small and calm, this line item rounds to zero. If it is large and churning with month-long retention, the backup dimension alone can exceed what the entire storage footprint would cost on owned disks.

The defaults audit: three settings to check today​

Whether or not you ever leave Fly, the billing change turned three previously inconsequential settings into cost controls. They are worth ten minutes:

  1. Retention per volume. The default is 5 days and the range is 1–60. Every volume that does not need multi-week recovery history — caches, scratch space, ephemeral build state that somehow ended up on a volume — should sit at the low end. Since snapshots are incremental, cutting retention helps most on frequently updated volumes.
  2. The disable switch. Fly added a per-volume option to turn off automatic snapshots entirely. That is the right call for data you can regenerate or already back up another way — but remember the warning in the docs: a Fly volume exists on exactly one server, so disabling snapshots on a volume with no other backup strategy means a host failure takes the data with it.
  3. Orphaned capacity. Volumes bill at $0.15/GB whether attached or not, and stopped Machines keep billing rootfs at the same rate. A volume left behind by a deleted app, or a stopped Machine nobody restarted, keeps charging full storage price indefinitely. fly volumes list across your apps is the cheapest cost review you will run this quarter.

One more operational note: because snapshots cannot be manually deleted, there is no "purge now" button when you discover a bloated chain. Lowering retention only stops the growth; the existing snapshots bill until they expire naturally. Fly gave everyone that grace implicitly — existing snapshots had months to expire before billing began — but going forward, the only fast control is the retention knob turned before the chain grows.

The honest counterweight: when the hosted backup dimension wins​

A cost comparison that only totals the invoice is lying by omission, so here is the other side. For the small stack in our worked example, Fly's snapshot line is $1.44 against $0.31 of Hetzner snapshot storage — a $1.13 monthly premium that buys automatic daily snapshots with zero operational work: no cron job, no retention script, no 3 a.m. discovery that backups silently stopped six weeks ago. Inside the free tier it is literally $0.00 for a backup story most side projects would otherwise never build. That is a genuinely good deal, and it is why Fly could truthfully say 98% of customers see no charges.

Self-hosting the backup dimension is cheap in storage and expensive in attention. Hetzner's per-GB snapshot rates are roughly one-seventh of Fly's, but Hetzner volume snapshots are manual: you schedule them, you rotate them, you verify restores. The forcing function that makes hosted backups valuable is not the storage — it is the default. Default-on daily snapshots with 5-day retention mean every Fly tenant has a recovery story on day one, including the ones who would never have built one. Any self-hosted platform that wants to match that has to make its backup story equally default-on, not equally cheap-per-gigabyte.

So the decision rule is simple: if your data fits comfortably in the free tier, the hosted backup dimension wins on every axis — cost included. If your data has outgrown it by an order of magnitude, the per-GB gap starts paying for real operational automation. The break-even is not a fixed number; it is the point where your snapshot line exceeds the cost of the backup runbook you would have to write anyway.

Backups are the template, not the exception​

Step back from Fly specifically and the pattern is worth naming: usage-billed platforms grow revenue by metering dimensions that used to be bundled, and backup storage is the ideal candidate — valuable, invisible, and scaling with success rather than with conscious consumption. Snapshot billing arrived with a free tier, incremental metering, and advance notice; it is about as fair a version of this move as exists. It still quietly added a compounding line item to every growing tenant's bill.

The defense is not outrage, it is instrumentation. Know your stored-versus-provisioned ratio, know your retention settings per volume, and know the per-GB rate your growth compounds against. Run those three numbers once a quarter and no default-on dimension can surprise you — on Fly, or anywhere else usage billing follows.

Self-hosting the whole stack changes this math from a metered line item into a fixed disk cost. Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, where your backup retention is a config value, not an invoice line. Star the repo on GitHub or deploy your first app today.

Related articles

Check your move before you migrate

Free browser tools: check a render.yaml or your Render scripts against bex, or turn a Heroku app or docker-compose.yml into a draft render.yaml. Nothing you paste leaves your browser.

Open the migration tools