Skip to main content

Playground · research instrument

Privacy-first

Edge DB Sync Lab

Place a primary and read replicas at real Fly.io regions, then fire transactions from anywhere on Earth. Reads return from the nearest replica in one short hop; writes animate their forward to the primary — the LiteFS/SQLite edge pattern, with all latency math disclosed.

Independent research instrument — not claimed as MakerPortal shipped product code. Methods, equations, assumptions, and limitations are disclosed so you can inspect what the page does and does not establish.

Read the field note →

Replication simulator

Topology & traffic

Click a region marker to apply the selected action; click open ocean/land to fire a client transaction from that point.

Primaryiad
Replicasams, sin, syd
Last read (model)
Last write (model)
Mean read / write— / —
Transactions0
Model, not measurement: latencies are simulated — great-circle distance ÷ (c/1.468 fiber speed) × 1.5 route factor + 1 ms/hop. Real RTTs vary with actual cable paths and load. Full math below.

World map — real Fly.io region locations · Natural Earth geometry, self-hosted

loading land…
Interactive Fly region topology map. Use the region selector and Apply at region button above for keyboard access.

primary · replica · unused region · read path · write forward

SponsorSponsor this simulator. Reach engineering practitioners.
Details ↗

Read vs write latency — last 40 transactions (model)

Latency history for the last 40 modeled transactions.

Anatomy: one writer, many readers

  1. 01

    SQLite stays SQLite. LiteFS is a FUSE layer under the database file. The app on every node opens app.db normally — no client library, no wire protocol, reads are local file I/O with microsecond latency.

  2. 02

    Primary election. A Consul lease guarantees exactly one writer. When the primary's lease lapses (deploy, crash), a candidate replica promotes — the .primary file on each replica always names the current one.

  3. 03

    Page-level replication. Committed transactions ship as LTX page sets in commit order. Replicas apply them atomically — a replica never serves a torn transaction, only a slightly older complete one.

  4. 04

    Write forwarding. A write landing on a replica answers with fly-replay: instance=<primary>; the router replays the request in the primary region. That is the long rose-colored arc in the simulation — the price of the single-writer guarantee.

primaryiad ✍replicaams 👁replicasin 👁replicasyd 👁LTX page stream (async, commit order)reads: local file · writes: fly-replay → iad

Single-writer, many-reader. Every guarantee and every cost in this lab follows from that one arrow direction.

Gear behind this build

Home edge lab · 6 picks

SBCs · storage6

More gear across every app: the full Gear list →

Hardware Kit Builder

Two Pis on your LAN make a real LiteFS primary/replica pair — measure actual replication, not a model.

Build this lab

Home edge-replica lab

Two Pis + fast external SSD = a physical two-region LiteFS/SQLite replication lab on your LAN — measure real read-local vs write-forward latency before renting cloud regions.

Prices shown were retrieved from the Amazon Product Advertising API on 19 July 2026 and are indicative only — the price and availability on Amazon at the time of purchase apply.

Prices shown were checked against the Amazon product listing on 9 August 2026 and are indicative only — the price and availability on Amazon at the time of purchase apply.

Estimated total

$530

Prices from Amazon catalog cache · may change

Open primary listing ↗

Kit Total

Buy ↗

The latency model, in full

Great-circle distance

d=2Rarcsinsin2Δϕ2+cosϕ1cosϕ2sin2Δλ2d = 2R \arcsin\sqrt{\sin^2\tfrac{\Delta\phi}{2} + \cos\phi_1\cos\phi_2\sin^2\tfrac{\Delta\lambda}{2}}

Haversine on a sphere of R = 6371 km. Numerically stable for the short hops (client → local replica) where the naive arccos formula loses precision.

Fiber propagation

tprop=dkroutec/n,n=1.468,  kroute=1.5t_{prop} = \frac{d \cdot k_{route}}{c / n},\quad n = 1.468,\; k_{route} = 1.5

Light in silica travels at c/1.468 ≈ 204,000 km/s — the single hardest constraint in distributed systems. k accounts for cables not following great circles. Both constants are stated, not hidden.

Transaction cost

tread=RTT(c,r)twrite=RTT(c,r)+RTT(r,P)t_{read} = RTT(c, r^*) \qquad t_{write} = RTT(c, r^*) + RTT(r^*, P)

r* = nearest replica to client c, P = primary. Each RTT = 2·t_prop + 1 ms processing. The write's second term is the fly-replay forward — the whole architectural argument in one sum.

What the model deliberately omits

TCP/TLS handshakes (amortized by connection pooling), congestion and jitter, replication lag on the read path (async — a replica may serve slightly stale data at zero latency cost), and fsync time at the primary. Omissions all favor no side: handshakes penalize both paths equally; replication lag is a consistency cost, not a latency one. For measured numbers, deploy the litefs.yml below and run real pings.

Production pattern — write forwarding in ~10 lines

The middleware that turns the simulation into a running system, plus a replica-safe litefs.yml. Fly.io ↗ runs LiteFS as a first-class pattern; the same code works anywhere FUSE does.

// Write-forwarding middleware (Hono/Express-style) — the whole trick.
// Reads hit local SQLite replica; writes replay to the primary region.
import { readFileSync, existsSync } from 'node:fs';

const PRIMARY_FILE = '/litefs/.primary'; // LiteFS writes this on replicas

function primaryRegion(): string | null {
  // On the primary this file doesn't exist; on replicas it names the primary.
  return existsSync(PRIMARY_FILE)
    ? readFileSync(PRIMARY_FILE, 'utf8').trim()
    : null;
}

export function forwardWrites(req: Request): Response | null {
  const isWrite = !['GET', 'HEAD', 'OPTIONS'].includes(req.method);
  const primary = primaryRegion();
  if (isWrite && primary) {
    // Fly's proxy replays the full request in the primary's region.
    return new Response(null, {
      status: 409,
      headers: { 'fly-replay': `instance=${primary}` },
    });
  }
  return null; // handle locally — reads are always local
}

/* litefs.yml (replica-safe defaults):
fuse:
  dir: "/litefs"
data:
  dir: "/var/lib/litefs"
lease:
  type: "consul"
  candidate: ${FLY_REGION == PRIMARY_REGION}   # only primary region runs candidates
  promote: true
proxy:
  addr: ":8080"
  target: "localhost:8081"
  db: "app.db"
  passthrough: ["/health"]
*/

Export · Soft gate

Export topology + latency matrix

Place primary and read replicas across Fly.io regions. Watch reads hit local replicas while writes forward with speed-of-light fiber latency math.

File · edge-topology-report.json

edge-topology-report.jsonapplication/json+ watermark line on free path

Free download adds a small footer: /* Export from makerportal.ai — free watermarked build. Unlock …Clean export removes footer. Both are generated fresh from your current sim tuning.

Privacy: email stays in your browser localStorage (mp_export_email_fly-edge-db-lab) + unlock flag (mp_export_unlock_fly-edge-db-lab). If Buttondown username is configured, we also POST to Buttondown (privacy-first mode, no tracking pixels per D-014). See privacy → affiliates & email.

Unlock clean export

Soft gate — no hard paywall, no Clerk. Email stays local unless you explicitly check the newsletter box. Unsubscribe anytime. RSS at /rss.xml.

Export → Fab bonusAfter export, your tuned stackup can be ordered via PCBWay/JLCPCB CTA (when live) — see /privacy#affiliates for live merchants.

Frequently asked questions

Are these real measured pings to Fly.io regions?

No — and the page says so everywhere a number appears. Latencies come from a physics model: great-circle distance, light propagating at c/1.468 in fiber (≈ 204,000 km/s), a 1.5× route-inflation factor for real cable paths, and 1 ms per-hop processing. That model lands within tens of percent of real inter-region RTTs, which is enough to make the architectural point: reads from a local replica are one short round trip; writes pay the full trip to the primary. Your real numbers will differ — deploy and measure.

What is LiteFS actually doing under the hood?

LiteFS is a FUSE filesystem that sits under SQLite. On the primary it intercepts committed transactions at the page level and streams them to replicas as an ordered log (LTX files); replicas apply pages and serve plain read-only SQLite. There is exactly one writer — a lease (via Consul) elects the primary. Nothing about SQLite itself changes; your app opens the same database file.

How do writes from a user in Sydney reach a primary in Virginia?

Write forwarding. The Sydney replica cannot commit, so the app responds with a fly-replay: region=iad header (or proxies internally); Fly's router replays the whole HTTP request in the primary region, the write commits there, and replication streams the new pages back out. The Code section shows the ~10-line middleware that implements this — the simulation animates exactly this path.

When does this architecture stop making sense?

When your write fraction gets large or writes need low latency from every geography (every write pays the trip to one primary), when replicas must never serve stale reads (replication is asynchronous — read-your-writes needs session pinning or waiting on replication position), or when a single write region becomes a compliance problem. The lab makes the first two visible: crank up write traffic and watch the advantage evaporate.

Shareable still

The instrument, captured—not illustrated.

This 16:9 frame is rendered from the real browser instrument above. It is the page's canonical preview for image search, link unfurls, and posts that need to show what the tool actually does.

Download 1280 × 720 JPEG
Edge DB Sync Lab — live MakerPortal instrument screenshot
Canonical capture · real UI · no generated scientific artwork