Fly.io occupies a specific niche between traditional VPS hosting and serverless functions: run full applications, including ones with persistent state, distributed across a global network of regions close to your actual users.
Fly.io is a deployment platform that runs applications as Firecracker microVMs (the same lightweight virtualization technology behind AWS Lambda) across a global network of physical regions. Unlike pure serverless functions platforms, Fly.io runs full, long-lived processes — meaning WebSocket servers, background workers, and stateful applications work naturally, not just request/response functions.
Why Fly.io Matters (and When to Skip It)
Many serverless platforms optimize for stateless request/response functions, which is a poor fit for WebSocket servers, long-running processes, or apps needing local disk state. Fly.io's microVM model runs your actual application process (via a Dockerfile), giving you the flexibility of a real server combined with genuinely global, low-latency deployment across regions close to users.
Skip Fly.io if your workload is a good fit for pure serverless functions (short-lived, stateless, bursty) where a platform like Vercel's function model or Cloudflare Workers might be simpler and cheaper — Fly.io's flexibility comes with more infrastructure concepts to manage than a pure functions platform.
Getting Started with Fly.io
fly launch # detects your app, generates fly.toml
fly deploy
A fly.toml configuration file:
app = "my-app"
primary_region = "iad"
[build]
[http_service]
internal_port = 3000
force_https = true
auto_stop_machines = true
auto_start_machines = true
min_machines_running = 1
[[vm]]
cpu_kind = "shared"
cpus = 1
memory_mb = 512
Deploying to multiple regions for global low latency:
fly regions add fra syd
fly scale count 3 --region iad,fra,syd
Core Fly.io Concepts Every Developer Should Know
Machines are Fly.io's core compute primitive — fast-starting Firecracker microVMs that can be started, stopped, and scaled programmatically, giving you server-like flexibility with much of serverless's operational simplicity.
auto_stop_machines/auto_start_machines provide scale-to-zero behavior for cost efficiency on low-traffic apps, similar in spirit to Neon's scale-to-zero for databases — machines stop when idle and start again on the next incoming request, at the cost of a brief cold start.
Persistent volumes attach local disk storage to specific machines, useful for apps needing local state (like an embedded database or file cache) that wouldn't survive on purely ephemeral compute:
[mounts]
source = "data"
destination = "/data"
Multi-region deployment is a first-class, straightforward feature, not a complex add-on — running your app in regions close to your actual user base is often just a config change and a scale command, meaningfully reducing latency for a genuinely global audience.
Common Fly.io Mistakes and How to Fix Them
Mistake 1: deploying to a single region for a genuinely global user base. This leaves real latency on the table for users far from that one region. Fix: identify where your users actually are and deploy machines in regions close to them.
Mistake 2: not configuring health checks properly, leading to traffic routed to unhealthy machines. Fix: define accurate HTTP or TCP health checks in fly.toml so Fly.io can correctly route around unhealthy instances.
Mistake 3: relying on local machine state without a persistent volume, then losing data on restart. Ephemeral machine storage doesn't survive a stop/start cycle without an explicitly mounted volume. Fix: use Fly Volumes for any state that needs to survive machine restarts, or move that state to a proper external database.
When Should You Use Fly.io Instead of Vercel or Serverless Functions?
Use Fly.io when your app needs long-running processes, WebSocket connections, background workers, or local state — cases that don't fit cleanly into a stateless serverless function model. Use Vercel, Cloudflare Workers, or similar serverless platforms when your workload is genuinely request/response and stateless, where their simpler operational model and often lower cost at low-to-moderate traffic wins.
Fly.io in Production
Set min_machines_running above zero for latency-sensitive production services to avoid cold-start delay on the first request after idle periods, while leaving less critical services free to scale to zero for cost savings. Also monitor machine health and region distribution regularly as your user base grows or shifts, since the value of multi-region deployment depends on it actually matching where your traffic originates.
If your app needs WebSockets, background jobs, or persistent local state and you've been fighting a pure serverless platform to make it work, Fly.io is worth evaluating specifically for that fit.