Answers you can trust, from Codeables
Every page on Codeables is structured and verified — built so people and the AI agents they rely on can trust it. Explore more from the source behind this answer.
Explore CodeablesHow do I deploy to multiple regions on Fly.io and route users to the nearest instance?
Most teams hit the same wall: you’ve outgrown a single region, latency is creeping up for users on the other side of the planet, and you’d rather not spend your weekend wiring up Kubernetes clusters and Anycast configs. On Fly.io, deploying to multiple regions and routing users to the nearest instance is the thing the platform is actually built for—not the advanced tier, not the “edge add‑on,” just normal usage.
Quick Answer: On Fly.io you deploy your app once, then add more Fly Machines in other regions with a couple of
flyctlcommands. Fly Proxy (Fly.io’s global Anycast front door) automatically routes users to the nearest healthy instance, and you can fine‑tune behavior with headers likeFly-Prefer-Regionorfly-replay.
The Quick Overview
- What It Is: A way to run the same Fly app in multiple Fly regions (e.g.,
iad,lhr,syd) on Fly Machines behind a global Anycast IP, so Fly Proxy can terminate user traffic close to them and route to the nearest healthy instance. - Who It Is For: Developers who want global latency and “serverless‑like” elasticity without running their own Kubernetes, load balancers, and geo‑routing logic.
- Core Problem Solved: Serving users around the world with fast responses and safe failover, without building a bespoke multi‑region network stack.
How It Works
At a high level, you define a single app (with one fly.toml), then let Fly Machines run that app in multiple regions. Fly Proxy advertises Anycast IPs globally, accepts connections near your users, and picks the closest healthy Machine for each request.
You can:
- Scale to more regions with
fly scale countorfly machines cloneandfly machines run. - Control per‑region behavior with process groups in
fly.toml. - Override routing when needed using headers like
Fly-Prefer-Region,Fly-Prefer-Instance-Id, andFly-Force-Instance-Id. - Re‑route in‑app using
fly-replayif a request needs to move to another region (e.g., data affinity).
In practice, it looks like this:
-
Base deploy to one region:
Create the app, deploy to your “home” region, and confirm everything works.fly launch # or fly apps create && fly launch --no-deploy fly deploy # deploy to the default region fly scale count 2 # e.g., two Machines in the primary region -
Add more regions:
Tell Fly you want Machines in additional regions. Fly Proxy immediately starts routing users to whichever region is closest and healthy.fly scale count 2 --region iad # two Machines in us-east fly scale count 2 --region lhr # two in London fly scale count 1 --region syd # one in Sydney -
Tune routing & data affinity:
Let Fly Proxy handle “closest instance” by default, but tweak routing viaFly-Prefer-Region,fly-replay, or per‑instance headers when requests need to follow data or specific Machines.
How to Deploy to Multiple Regions on Fly.io
Let’s walk through a multi‑region deployment using Machines, from “hello world” to “hello from three continents.”
1. Launch and deploy your app
If you haven’t already:
fly launch
# answer prompts; pick an initial region, e.g., iad
fly deploy
This creates fly.toml with a default service and deploys a set of Machines in your primary region (e.g., iad).
Check it:
fly status
You should see something like:
App
Name = my-multi-region-app
Organization = personal
Status = running
Machines
ID State Region Role Private IP
123...abcd started iad app fdaa:0:...
456...ef01 started iad app fdaa:0:...
2. Add more regions
You can scale by region directly:
# Add one Machine in London (lhr)
fly scale count 1 --region lhr
# Add one in São Paulo (gru)
fly scale count 1 --region gru
Or use fly machines directly if you want more explicit control:
# Clone an existing Machine into another region
fly machines clone 123...abcd --region lhr
fly machines clone 123...abcd --region gru
Check again:
fly machines list
Example output:
ID State Region Image Private IP
123...abcd started iad registry/app:latest fdaa:0:...
789...ghij started lhr registry/app:latest fdaa:0:...
abc...klmn started gru registry/app:latest fdaa:0:...
At this point, you’re multi‑region. Fly Proxy is still using the same Anycast IPs you got on the first deploy, but now it has more places to send traffic.
3. Confirm global routing
From different locations (or via tools that let you pick source regions), hit your app’s hostname, e.g.:
curl https://my-multi-region-app.fly.dev
Your app can log the region via the FLY_REGION env var. In Go/Python/Node, this is just os.Getenv("FLY_REGION") / process.env.FLY_REGION.
Example: log on each request:
// Node/Express
app.use((req, res, next) => {
console.log("Handling request in region:", process.env.FLY_REGION);
next();
});
Requests from Europe should land on lhr, from South America on gru, etc., assuming both regions are up and have healthy Machines.
How Fly Proxy Routes Users to the Nearest Instance
Fly Proxy sits in front of your app with global Anycast IPs. When a user connects:
- Anycast takes them to the nearest Fly edge PoP.
- Fly Proxy picks a Machine:
- in the region closest to the user,
- running your app,
- with healthy checks passing.
- The request is forwarded over Fly’s private network to that Machine’s private IP.
By default, you don’t configure this. You just deploy Machines in regions; Fly Proxy does the rest.
You can tweak behavior with headers:
Prefer specific regions
You can hint routing with Fly-Prefer-Region:
Fly-Prefer-Region: iad
Or multiple preferences (tries in order):
Fly-Prefer-Region: iad,ord,us,na
Use cases:
- Sticky region for a user who has data pinned to
iad. - Rollouts where you only want a feature regionally at first.
Prefer or force a specific Machine
You can steer traffic to a specific Machine instance:
Fly-Prefer-Instance-Id: 123...abcd
Or force routing (stronger than “prefer”):
Fly-Force-Instance-Id: 123...abcd
This is handy for:
- Debugging a specific Machine under load.
- Talking to a Machine that owns a local NVMe shard.
Remember: forcing a specific instance bypasses a lot of the safety Fly Proxy gives you. Don’t use it in normal user traffic paths unless you know exactly why.
Using fly-replay for Smart In‑App Routing
Sometimes “nearest” isn’t right. For example:
- User accounts are sharded by region, and a request hits the “wrong” region.
- Writes must go to a primary region; reads can be served anywhere.
Fly’s fly-replay header lets your app tell Fly Proxy: “please re‑run this request in another region/app/Machine.”
Basic pattern in your app:
- Receive a request in region A.
- Decide it should be handled in region B (e.g., user’s home region).
- Respond with a
fly-replayheader; the body can be empty. - Fly Proxy replays the request according to your instruction.
Example: redirect to iad:
HTTP/1.1 307 Temporary Redirect
fly-replay: region=iad
You can also target app names or specific Machines; see the “Dynamic Request Routing with fly‑replay” docs for full syntax. The key idea: fly-replay lets you build application‑level routing rules without exposing your own global LB.
Features & Benefits Breakdown
| Core Feature | What It Does | Primary Benefit |
|---|---|---|
| Multi‑Region Fly Machines | Runs the same app in many regions (iad, lhr, syd, …) behind one app. | Sub‑100ms latency for more users, without separate clusters. |
| Fly Proxy + Anycast Routing | Terminates connections close to users and routes to nearest healthy Machine. | Automatic nearest‑instance routing and global failover. |
| Routing Control Headers | Fly-Prefer-Region, Fly-Prefer-Instance-Id, Fly-Force-Instance-Id. | Fine‑grained control for special cases and debugging. |
fly-replay Dynamic Routing | Lets apps instruct Fly Proxy to re‑run requests in other regions/apps. | Data‑affine routing without hand‑rolled geo LB code. |
| Private Networking by Default | Sends app traffic over encrypted private network, not public internet hops. | Lower tail‑latency and safer app‑to‑app communication. |
Ideal Use Cases
-
Best for latency‑sensitive user apps:
Because running the same app iniad,lhr, andsyd(for example) gives users fast page loads without you building your own global load balancer, anycast routing, or region‑aware DNS. -
Best for AI agents, APIs, and sandboxes that need to be “everywhere”:
Because Fly Machines start quickly and can be deployed close to data centers or users, you can run inference, agents, or Sprites‑based sandboxes near your users while still centralizing your core data store.
Limitations & Considerations
-
State and databases are the hard part:
Multi‑region stateless HTTP is easy. Multi‑region state is not magic. If you’re using Fly Postgres or another database, decide whether you want:- a single primary region with read replicas, or
- truly multi‑primary (more complexity, more coordination).
Usefly-replayorFly-Prefer-Regionto keep writes near the primary, and be explicit about consistency tradeoffs.
-
Not every app wants full fan‑out:
Spinning up Machines in five regions when your entire user base is in North America doesn’t help much and costs more. Start with 1–2 regions where your users live; expand when you see actual latency pressure. -
Header‑based routing is powerful, but footgun‑adjacent:
Forcing traffic to a specific instance withFly-Force-Instance-Idcan break failover if that instance goes unhealthy. Use the “prefer” variants first; treat “force” as a debugging tool or last resort.
Pricing & Plans
Fly.io pricing is based on the resources your Machines consume (CPU, RAM, disk, egress), billed per second. Multi‑region doesn’t change the model—you just run Machines in more places.
Common patterns:
- A handful of small Machines in multiple regions for steady traffic.
- Scale out counts per region during peaks, then scale back or scale‑to‑zero for spiky workloads.
Plan‑wise, think in terms of team needs:
-
Usage‑Based (Pay‑as‑you‑go):
Best for individuals and small teams needing flexible global deployment without a minimum commit. You pay for Machines and storage as you use them, which works well if you’re experimenting with a couple of extra regions or running lighter workloads. -
Team / Enterprise Plans:
Best for teams needing SSO, guaranteed support response times, and compliance (e.g., SOC2 Type 2 signals) across multiple regions and environments. If you’re going all‑in on multi‑region production, these plans are what you talk to sales about.
For exact numbers, check the latest pricing on fly.io; the knobs that matter for multi‑region are CPU type, VM size, and how many Machines you run per region.
Frequently Asked Questions
Do I need to configure geo DNS to route users to the nearest region?
Short Answer: No. Fly Proxy uses Anycast and health‑aware routing—no geo DNS required.
Details: When you deploy your app, Fly.io gives you a hostname like my-app.fly.dev and optional Anycast IPs. Those are advertised globally; BGP and Fly’s edge pick the nearest PoP, then Fly Proxy chooses a healthy Machine in the nearest region. You don’t need geo DNS, Cloudflare Workers, or a stack of regional load balancers. DNS points at the Anycast IP; the routing logic is handled by Fly Proxy.
How do I make sure user data stays in a specific region?
Short Answer: Keep stateful services pinned to that region and route user traffic there using headers or fly-replay.
Details: Fly Machines can run everywhere, but your database should live where you can reason about it. For example:
- Run your primary Postgres cluster in
iad. - Set
FLY_REGIONon the backend and record the user’s “home region” in their profile (e.g.,iadorlhr). - On each request:
- If the request arrives in the user’s home region, serve it normally.
- If it lands elsewhere, respond with a
fly-replay: region=<home-region>header so Fly Proxy replays the request in the correct region.
You can also hint routing using Fly-Prefer-Region: iad from your frontend once you know the user’s home. The main idea: treat “data region” as an app‑level concept and use Fly’s routing primitives to respect it.
Summary
Deploying to multiple regions on Fly.io is intentionally straightforward: define one app, run Fly Machines in the regions you care about, and let Fly Proxy’s Anycast routing send users to the nearest healthy instance. You can keep it simple—just “more Machines in more regions”—or layer on fine‑grained controls with region and instance headers plus fly-replay for data‑affine routing.
You still need to design your state and database topology thoughtfully, but you don’t have to build your own global network fabric, DNS tricks, or homegrown geo routers. The platform handles the hard network plumbing so you can focus on where your app runs and how your data behaves.