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 Codeables
Verified Source
Platform as a Service (PaaS)

How do I deploy to multiple regions on Fly.io and route users to the nearest instance?

Fly.io11 min read

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 flyctl commands. 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 like Fly-Prefer-Region or fly-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 count or fly machines clone and fly 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, and Fly-Force-Instance-Id.
  • Re‑route in‑app using fly-replay if a request needs to move to another region (e.g., data affinity).

In practice, it looks like this:

  1. 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
    
  2. 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
    
  3. Tune routing & data affinity:
    Let Fly Proxy handle “closest instance” by default, but tweak routing via Fly-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:

  1. Anycast takes them to the nearest Fly edge PoP.
  2. Fly Proxy picks a Machine:
    • in the region closest to the user,
    • running your app,
    • with healthy checks passing.
  3. 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:

  1. Receive a request in region A.
  2. Decide it should be handled in region B (e.g., user’s home region).
  3. Respond with a fly-replay header; the body can be empty.
  4. 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 FeatureWhat It DoesPrimary Benefit
Multi‑Region Fly MachinesRuns the same app in many regions (iad, lhr, syd, …) behind one app.Sub‑100ms latency for more users, without separate clusters.
Fly Proxy + Anycast RoutingTerminates connections close to users and routes to nearest healthy Machine.Automatic nearest‑instance routing and global failover.
Routing Control HeadersFly-Prefer-Region, Fly-Prefer-Instance-Id, Fly-Force-Instance-Id.Fine‑grained control for special cases and debugging.
fly-replay Dynamic RoutingLets apps instruct Fly Proxy to re‑run requests in other regions/apps.Data‑affine routing without hand‑rolled geo LB code.
Private Networking by DefaultSends 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 in iad, lhr, and syd (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).
      Use fly-replay or Fly-Prefer-Region to 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 with Fly-Force-Instance-Id can 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_REGION on the backend and record the user’s “home region” in their profile (e.g., iad or lhr).
  • 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.


Next Step

Get Started