CodeWorlds
Back to collections
Guide18 min readCodeWorlds Team

Fly.io, micro VMs that sleep down to zero

Fly.io runs a container image as a virtual machine near your users. Per-second billing, autostop to zero, transfer prices, and the volume trap explained.

Fly.io, micro VMs that sleep down to zero

Fly.io takes a container image and runs it as a separate virtual machine in one of the eighteen regions listed in its price list, charging for the seconds it runs. A machine with no traffic can be stopped by the proxy, and then you pay only for its file system. The price of that convenience sits elsewhere: in data pinned to one server in one region.

What Fly.io actually runs

The base unit is a Fly Machine, which the documentation describes plainly as a virtual machine rather than a process in a container sharing its environment with neighbours. You supply an OCI-compatible image or a Dockerfile that Fly builds into one, and the platform turns it into a machine in the region you choose. An application, a Fly App, is a bag for machines: it may hold one, or ten spread across five regions.

Fly Proxy sits in front of the machines. It terminates TLS, spreads traffic across machines, routes a request to the nearest region and, most importantly for this text, can stop and start machines based on traffic. Addressing works like this: every app gets a shared IPv4 address and any number of anycast IPv6 addresses for free, while a dedicated IPv4 costs 2 dollars a month.

A machine's file system is ephemeral and slow. The documentation gives a hard ceiling: at most 2000 input and output operations per second and 8 MiB per second of bandwidth, no matter how large a machine you pick. Anything that has to survive a deployment and has to be fast must live on a Fly Volume or in a database outside the machine.

The rest of the offering grew around that core. Managed Postgres is a managed PostgreSQL inside the organisation's private network. Extensions are third-party services sold through the Fly bill, among them Tigris object storage and Redis from Upstash. Fly Kubernetes is a managed cluster at 75 dollars a month plus the cost of the machines and volumes you create inside it. A machine can be started, stopped or suspended, and those three states bill completely differently.

The first deployment and the fly.toml file

Getting into a project looks the same for every language, because everything reduces to an image.

Code
Bash
# install the command line tool
curl -L https://fly.io/install.sh | sh

fly auth login

# detect the framework, generate fly.toml and possibly a Dockerfile
fly launch

# deploy without a confirmation prompt
fly deploy --now

# one machine instead of a spare pair
fly deploy --ha=false

# deploy to selected regions only
fly deploy --regions ams,ord

# replacement strategy: canary, rolling, bluegreen or immediate
fly deploy --strategy bluegreen

fly status
fly logs
fly ssh console

One item on that list tends to surprise people on the first invoice. The --ha flag defaults to true, meaning a deployment creates spare machines that raise app availability. A freshly launched project therefore starts with two machines rather than one, and you pay for both. If you are building a staging environment, --ha=false is a sensible setting from day one.

Configuration lives in a fly.toml file at the project root.

Code
TOML
app = "shop-demo"
primary_region = "ams"

[build]
  dockerfile = "Dockerfile"

[env]
  PORT = "8080"
  NODE_ENV = "production"

[http_service]
  internal_port = 8080
  force_https = true
  auto_stop_machines = "suspend"
  auto_start_machines = true
  min_machines_running = 0

  [http_service.concurrency]
    type = "requests"
    soft_limit = 200
    hard_limit = 250

[[vm]]
  size = "shared-cpu-1x"
  memory = "512mb"
  cpu_kind = "shared"
  cpus = 1

[mounts]
  source = "shop_data"
  destination = "/data"
  initial_size = "10gb"
  snapshot_retention = 14

The primary_region field decides where fly deploy creates new machines and reaches the machine as the PRIMARY_REGION environment variable. The [[vm]] section is optional, but leaving it out has a consequence: without it, deployment commands do not try to enforce machine size, and fly scale count on an empty app falls back to shared-cpu-1x. The reverse trap is worse. If you grow a machine with fly scale vm while the file still carries a [[vm]] section with the old size, the next fly deploy reverts the change.

The [mounts] section requires two fields, source and destination, and destination cannot be the root directory. The initial_size field applies only to fly launch and fly deploy when a new volume has to be created, and is ignored by fly volume create. Snapshot retention defaults to five days, with a minimum of one and a maximum of sixty.

Machines that sleep and wake on demand

Autostop and autostart are the reason this hosting looks cheap at all under uneven traffic. A stopped or suspended machine costs you nothing in CPU or memory, only its file system.

The stopping rule is specific and worth knowing before you wonder why nothing goes to sleep. Every few minutes the proxy checks for excess capacity in each region separately. When a region holds more than one machine, it computes excess = number of machines - (number of machines over soft_limit + 1) and stops exactly one machine if the result is one or greater. One pass means one machine per region, so going from ten machines down to one takes several such cycles. When a single machine is left in a region, the proxy simply checks whether it has any traffic and puts it to sleep at zero load.

The auto_stop_machines value accepts "off", "stop" or "suspend", and the default when the field is absent is "off". That means an app without the field never falls asleep on its own. The "suspend" variant wakes faster than "stop" because the machine keeps its memory state, but the documentation notes caveats and says it is not always possible. The auto_start_machines field defaults to true and min_machines_running to zero, and that last number applies to the primary region only. Keeping one machine awake in the primary region does not prevent machines in other regions from sleeping.

The most important limitation is that the proxy never creates or destroys machines. Your scaling ceiling is the number of machines you created yourself through fly scale count or fly machine clone. Autostart only wakes what already exists. The documentation also warns that with thousands of machines in a single app the rate-limited loop becomes the constraint and most idle machines will stay running, because the proxy cannot stop them fast enough. For per-user development environments Fly then recommends one app per user with dynamic routing, or having the app shut itself down when idle.

Code
Bash
# list machines with regions and state
fly machine list

# manual stop and start
fly machine stop 3d8d9601a12345
fly machine start 3d8d9601a12345

# clone a machine into another region
fly machine clone 3d8d9601a12345 --region nrt

# two machines in Amsterdam, one in Tokyo
fly scale count 2 --region ams
fly scale count 1 --region nrt

# change size and memory
fly scale vm shared-cpu-2x
fly scale memory 1024

# available sizes and regions
fly platform vm-sizes
fly platform regions

Pricing and what is left of the free plan

Billing runs per organisation and per resource, with no bundles. A payment card is required for every organisation except those linked to a parent billing organisation.

A running machine costs the price of a named preset plus roughly 5 dollars per additional gigabyte of memory per thirty days. The smallest preset, shared-cpu-1x with 256 MB of memory, costs 0.0028 dollars an hour and lands between 1.94 and 2.43 dollars a month depending on the region, because the price list applies different regional markups. The same preset with 1 GB of memory is 5.92 dollars a month in the cheapest group, and performance-1x with 2 GB costs 32.19 dollars. A stopped machine costs only its file system: 0.15 dollars per gigabyte per thirty days. Reserving a block of compute gives a 40 percent discount, for instance 36 dollars up front for a year yields 5 dollars of monthly credit for shared machines in a specific region, with the credit not rolling over and applying only to CPU and additional memory.

Inbound traffic is free in full. Outbound is billed by region group, and organisations created after 18 July 2024 are automatically covered by rates that separate public from private traffic. Switching to those rates cannot be undone.

Region groupEgress to the public internetPrivate cross-region transfer
North America, Europe0.02 USD per GB0.006 USD per GB
Asia Pacific, Oceania, South America0.04 USD per GB0.015 USD per GB
Africa, India0.12 USD per GB0.050 USD per GB

Then come the small line items, which add up faster than they look. A single hostname certificate is 0.10 dollars a month, a wildcard one dollar, with the first ten single hostname certificates free per organisation. A static egress address for a machine costs 0.005 dollars an hour, roughly 3.60 dollars a month. Support beyond the community forum is paid: 29 dollars a month for the Standard package, 199 for Premium, from 2500 for Enterprise.

The history of the free plan matters here, because descriptions of a state from several years ago still circulate. Plans were discontinued on 7 October 2024 and are not sold to new customers. The old free allowances, meaning up to three shared-cpu-1x machines with 256 MB of memory, 3 GB of volumes, plus 100 GB of outbound traffic in North America and Europe and 30 GB in each of the other groups, are honoured only for organisations that held them before that date. Anyone who switches to pay-as-you-go cannot return to the old plan.

Today a new account gets a trial rather than a free plan. It covers two hours of machine runtime or seven days, whichever comes first. Inside it fit at most ten machines, 20 GB of volumes, up to two cores and 4 GB of memory per machine, and trial machines are configured to stop after five minutes of running. Dedicated IPv4 addresses and performance cores sit outside the trial. Once the limits or the seven days run out, apps stop running and you cannot launch new machines until a card is on file. Adding a card partway through ends the trial immediately, and everything counts toward the bill from that point.

Data pinned to a region

Here lies the real boundary of the idea of an app spread across the world. A Fly Volume is a slice of an NVMe drive on the same physical server that hosts the machine, and it is tied to that hardware. A volume belongs to one app, exists in one region on one server, and attaches to exactly one machine. It is not network storage, and the platform does not replicate data between volumes. If you want two copies to agree, your application has to make that happen.

The consequences are unforgiving, and the documentation states them outright, warning you to always provision at least two volumes per app. A drive failure under the only machine holding a volume means downtime, and with a single copy of the data it means losing it. Snapshots are taken daily with retention from one to sixty days, five by default, but Fly itself says they should not be your primary backup. Volumes cost 0.15 dollars per gigabyte per month of provisioned rather than used capacity, and you pay while the machine is stopped and while the volume is attached to nothing at all. Snapshots cost 0.08 dollars per gigabyte per month above the first 10 GB each month, a charge introduced on 1 January 2026 and first visible on the invoice issued in early February.

Managed Postgres does not remove that problem, it moves it up a level. Plans start with Basic at a shared core and 1 GB of memory for 38 dollars a month, through Starter with 2 GB at 72 dollars, Launch with a performance core and 8 GB at 282 dollars, Scale at 962 dollars, up to Performance at 1922 dollars. On top comes 0.28 dollars per provisioned gigabyte of storage per thirty days. The cluster is highly available, but it lives in one region, so a machine in Tokyo querying a database in Amsterdam pays in latency and, since February 2026, in private transfer at the rates in the table above.

Two things about Managed Postgres are easy not to learn in time. The database lives outside the app, so deleting the app does not delete the database and the charges keep running. The second is more serious: the documentation lists security patches and version upgrades as features still under development, alongside customer-facing alerting and migration tooling. For a service called managed, that caveat is worth reading twice before a production rollout. Self-run Fly Postgres still works, but the price list covers it under unsupported products.

The practical conclusion is that the stateless layer is global and the data is not. A sensible arrangement puts the database in one region, stateless machines near users, and a cache at the edge. Upstash Redis sold as an extension fits that last slot, with the price list caveat that data transfer to such third-party services is billed separately.

Licences and what is genuinely open

The platform is closed. The tooling around it is open, and this is where it gets interesting, because three licence sources do not say the same thing.

The command line tool, repository superfly/flyctl, carries a LICENSE file with the full Apache 2.0 text at its root, and the GitHub programming interface reports Apache-2.0 for it. The repository holds roughly 1695 stars, 310 forks, 216 open issues, is not archived, and its last change dates from 21 August 2026. The current release is v0.4.87 from 20 August 2026. The divergence sits in the published artefact: the release archive contains exactly one file, the flyctl binary, and no licence file at all. Anyone installing the tool through the install script gets a program with no licence text, even though the licence exists perfectly well in the repository.

The second case is worse. The Dockerfile generator for Node projects, package @flydotio/dockerfile at version 0.7.10, declares an MIT licence in the npm registry. The fly-apps/dockerfile-node repository has no licence file, and the GitHub licence endpoint returns a 404 for it. The published package contains no licence file either. The entire MIT claim is one field in package.json and nothing more. For a dependency audit that is not enough, and this package is what fly launch proposes to Node projects.

The third trap is about names. The npm registry holds a package called flyctl at version 1.2.11 under MIT, but it is a third-party wrapper around the official tool, with a repository outside the Fly organisation. Running npm install flyctl does not give you the official tool.

Two genuinely open pieces are used well beyond Fly. LiteFS, a distributed file system for replicating SQLite, is Apache 2.0 with roughly 4866 stars, though its last change dates from May 2026. Corrosion, a distributed state store, is also Apache 2.0, holds roughly 1829 stars and is actively developed.

Vendor lock-in is easy to estimate here. A container image moves anywhere. What does not move is fly.toml, the proxy behaviour with autostop, the private network with Flycast addresses, or the Machines API. The more logic you build on a machine waking on demand in a specific region, the more has to be rewritten when you move out.

Fly.io against the alternatives

FeatureFly.ioRailwayVercelNetlifyCoolify
Unit of executionvirtual machine from an OCI imagecontainer from an image or repositoryfunctions and static assets from a repositoryfunctions and static assets from a repositorycontainer on your own server
Sleeping to zeroyes, via the proxy, steered in fly.tomldepends on the planserverless model, no persistent machineserverless model, no persistent machineno, the server runs all the time
State and datavolume pinned to one server in one regionthe provider's database servicesnone, data with an external providernone, data with an external provideryour server's disks
Self-hostingnonononoyes, that is the point of the tool
Platform codeclosed, flyctl under Apache 2.0closedclosedclosedApache 2.0

The choice comes down to the shape of the application. If you have a long-lived process, WebSocket connections, background jobs, or an image that must be the same image locally and in production, Fly.io fits better than the serverless model of Vercel or Netlify. If you are building a framework-driven site and want preview deployments per branch without writing configuration, those platforms deliver that with no work. Railway sits closer to Fly.io in model, but gives less fine-grained control over placing machines in regions. If cost is the main driver and you want everything in your own hands, Coolify on your own server comes out cheaper, at the price of server maintenance becoming your job.

Common mistakes

The first is assuming the app sleeps by itself. The default for auto_stop_machines when the field is absent is "off", so a machine created by hand or copied from somebody else's configuration will grind away around the clock. Check the file rather than your intuition.

The second is forgotten volumes. You pay for provisioned capacity from the moment of creation, including while the volume is attached to no machine, and deleting a machine does not delete its volume. After experimenting, run through fly volume list in every app.

The third is a database left behind by a deleted app. Managed Postgres lives outside the app and removing the app does not touch the cluster, which on a 282 dollar a month plan hurts specifically.

The fourth is fly scale vm with a [[vm]] section still in the configuration file. A size change made from the command line gets reverted on the next deployment, because the file takes precedence.

The fifth is counting on autoscaling that does not exist. The proxy only wakes machines that already exist, so your traffic ceiling is set by fly scale count rather than by momentary load.

The sixth is spreading machines across the world with a database in one region. A machine in Sydney querying Postgres in Amsterdam gives worse response times than a single machine in Amsterdam, and since February 2026 it adds a private transfer charge on top.

The seventh is overlooking the --ha flag. A deployment creates spare machines by default, so a project meant to cost two dollars a month costs four.

The eighth is treating the trial as a free plan. Two hours of machine runtime end sooner than they look, especially when the machine never sleeps, and once they are gone the apps simply stop.

FAQ

Does Fly.io have a free plan?

No. Plans were discontinued on 7 October 2024, and the old free allowances are honoured only for organisations that already held them. A new account gets a trial: two hours of machine runtime or seven days, up to ten machines and 20 GB of volumes. A card is required for every organisation billed on its own.

What does the smallest always-on application cost?

One shared-cpu-1x machine with 256 MB of memory running without a break is 1.94 to 2.43 dollars a month depending on region. On top come a volume at 0.15 dollars per gigabyte, outbound traffic at 0.02 dollars per gigabyte in Europe and North America, and an optional dedicated IPv4 at 2 dollars.

What exactly happens to a machine with no traffic?

Every few minutes the proxy computes excess capacity in the region. With one machine in a region and zero load it stops or suspends it; with several machines it puts one to sleep per pass. A stopped machine costs only its file system, 0.15 dollars per gigabyte per thirty days.

Can a volume be replicated across regions?

Not automatically. A volume exists on one server in one region and the platform does not synchronise data between volumes. Replication is the application's job, through LiteFS for SQLite for instance, or through replication on the database side.

Is flyctl open source software?

The superfly/flyctl repository is under Apache 2.0 and the GitHub interface reports it as such. The release archive holds the binary alone, with no licence file. The platform itself, meaning the proxy and the machine management layer, stays closed.

When is Fly.io the wrong choice?

When the application is a static site with forms, since serverless platforms are simpler for that. When you need a database replicated across regions without writing it yourself. When you would rather not maintain your own Dockerfile or think about which region holds which disk.

Resource pricing is documented by Fly.io, trial terms live on a separate page, and the command line tool's source sits in the GitHub repository.

Read next

We use cookies to enhance your experience on the site