SQLite on the Edge: Replicating Databases with LiteFS and Fly.io
Learn how to deploy globally replicated, ultra-low latency SQLite databases using LiteFS and Fly.io. Step-by-step FUSE layer replication walkthrough.

Learn how to deploy globally replicated, ultra-low latency SQLite databases using LiteFS and Fly.io. Step-by-step FUSE layer replication walkthrough.
SQLite on the Edge: Replicating Databases with LiteFS and Fly.io
For decades, the standard architectural playbook for web applications was simple: place a massive, monolithic database (like Postgres or MySQL) in a single data center, and point all web servers—regardless of where users are located globally—to that single database.
As edge compute runtimes (such as Cloudflare Workers, Fly.io, and Vercel Edge) distributed application code across the globe, this old architecture became a major bottleneck. Running serverless code 20ms away from a user in Frankfurt is useless if every database query must cross the Atlantic to a single RDS instance in us-east-1, incurring a 100ms latency penalty on every roundtrip.
But what if you could run a lightweight, file-based database like SQLite directly in the edge container, and have it automatically replicate globally at the filesystem level?
Enter LiteFS.
In this article, we’ll explore how LiteFS intercepts filesystem calls using FUSE, handles active lease-based primary election, and enables you to deploy globally replicated, ultra-low latency SQLite databases on Fly.io.
⚡ 1. The Magic Under the Hood: Intercepting SQLite via FUSE
Unlike standard database replication engines (which operate at the SQL layer or binlog stream level), LiteFS operates directly at the operating system filesystem layer.
LiteFS mounts a FUSE (Filesystem in Userspace) directory at /var/lib/litefs. When your application writes to the SQLite database file inside this directory, LiteFS intercepts the kernel-level system calls (such as write(), fsync(), and truncate()).
[Your SQLite Application]
│ (SQL Query)
▼
[sqlite3 Library]
│ (Filesystem Calls: write, fsync)
▼
[Linux VFS Kernel]
│
▼
[LiteFS FUSE Driver] (Intercepts & translates bytes into Transaction Frame logs)
│
▼
[Physical Edge Disk]
By intercepting SQLite's write-ahead log (WAL) transactions, LiteFS extracts the exact pages modified in each transaction and packs them into lightweight, compressed cryptographic frame logs (.ltx files). These transaction frames are then broadcasted asynchronously to all read-only replica nodes across the globe.
🏗️ 2. Primary Election and Write Redirection
Replication requires a single source of truth to avoid split-brain conflicts. LiteFS handles this using a lease-based consensus protocol (integrated natively with Consul or Fly.io's internal Consul cluster).
- 2.The Primary Node: One node in your cluster acquires the write lease (usually the node nearest your primary application users). It is the only node permitted to modify the SQLite database file.
- 4.Replica Nodes: All other global nodes run as read-only replicas. They continuously stream
.ltxjournal pages from the primary node and apply them to their local SQLite files. - 6.Automatic Failover: If the primary node goes offline or suffers a network partition, the lease expires, and a replica node automatically wins a new lease, becoming the new primary.
Handling Writes on Replicas
Because SQLite replicas are strictly read-only, attempting to execute an INSERT or UPDATE statement on a replica node would normally fail with a SQLITE_READONLY error.
LiteFS handles this beautifully at the application layer or proxy layer. LiteFS provides an internal HTTP server on port 20205 that reports node status. You can configure a lightweight reverse proxy (like Nginx or an application middleware) to automatically inspect the Fly-Prefer-Region header and redirect mutating HTTP requests back to the primary region:
typescript// Express middleware example for write-redirection to LiteFS primary node import express from 'express'; const app = express(); const PRIMARY_REGION = 'iad'; // Virginia, USA app.use((req, res, next) => { const currentRegion = process.env.FLY_REGION || 'unknown'; // If the request is mutating (POST, PUT, DELETE) and we are on a replica node if (['POST', 'PUT', 'DELETE'].includes(req.method) && currentRegion !== PRIMARY_REGION) { // Redirect write request directly to the primary region via Fly-Replay header res.setHeader('Fly-Replay', `region=${PRIMARY_REGION}`); return res.sendStatus(409); // Conflict / Replay instruction } next(); });
🛠️ 3. Deploying LiteFS on Fly.io: Step-by-Step
Let's look at the configuration required to deploy a replicated SQLite database with LiteFS.
Step A: The litefs.yml Config File
Create a litefs.yml in your project root. This file tells LiteFS where to mount the FUSE directory, how to access Consul for leases, and where to store raw replication data.
yaml# /litefs.yml fuse: dir: "/var/lib/litefs" data: dir: "/var/lib/litefs-data" lease: type: "consul" candidate: true promote: true advertise-url: "http://${HOSTNAME}.vm.internal:20202" consul: url: "${FLY_CONSUL_URL}" key: "litefs/service-db" proxy: addr: ":8080" target: "localhost:8081" db: "production.db"
Step B: The Dockerfile Entrypoint
Because LiteFS needs to mount FUSE, it must run as the primary supervisor process in your container, launching your actual application process after mounting the database folder.
dockerfileFROM alpine:3.18 # Install FUSE, SQLite, and Ca-Certificates RUN apk add --no-cache fuse3 sqlite ca-certificates # Copy LiteFS binary from official repository COPY /usr/local/bin/litefs /usr/local/bin/litefs COPY /usr/local/bin/ltx /usr/local/bin/ltx # Copy configuration and application source COPY litefs.yml /etc/litefs.yml COPY my-app /usr/local/bin/my-app # Run LiteFS as supervisor ENTRYPOINT ["litefs", "mount", "--", "/usr/local/bin/my-app"]
🏁 4. Conclusion: Read-Heavy Edge Performance Unleashed
By executing replication directly at the FUSE filesystem layer, LiteFS combines the absolute simplicity of SQLite (a single, serverless file) with the scaling capabilities of a global edge architecture. Your read queries complete in less than 1ms directly from container memory, while write operations are safely coordinated through the lease system.
Deploying LiteFS on modern platforms like Fly.io is a game-changing move for read-heavy SaaS applications, dynamic blogs, and hyper-local web portals seeking production-ready edge durability at a fraction of cloud cost.

Bun 1.2 vs. Node.js 22 vs. Deno 2.0: The Ultimate 2026 HTTP Throughput & Memory Benchmark
A rigorous, standardized developer-focused comparison of the three primary JavaScript runtimes of 2026, measuring raw throughput, memory leaks, and package manager overhead.

Postgres Row Level Security (RLS): Building Multi-tenant SaaS Backends Safely
Ditch manual tenant filters. Learn how to secure multi-tenant SaaS applications at the database level using Postgres Row Level Security (RLS) policies.