All posts
Web Development
3 min read• 10/31/2026

Per-Tenant SQLite at the Edge: Ditching Centralized Read Replicas

Running a single global Postgres cluster is a bottleneck for multi-tenant web apps. Here is how we run isolated, embedded SQLite instances in edge workers to achieve zero-latency data access.

Share X LinkedIn

Tip: use ← / → to browse posts.

Per-Tenant SQLite at the Edge: Ditching Centralized Read Replicas
## The Distributed Postgres Fallacy For two decades, web development has relied on a shared architectural religion: deploy one massive, centralized relational database in `us-east-1`, place connection pools and Redis instances in front of it, and scatter read replicas across continental zones to serve distributed users. As modern edge runtimes (Cloudflare Workers, Fastly Compute, V8 Isolates) slashed compute latencies to under 10 milliseconds globally, our databases remained stubbornly tethered to physical data centers hundreds of miles away. Read replicas introduce brutal eventual consistency bugs. Global distributed locks cripple throughput. Meanwhile, multi-tenant databases carry inherent cross-tenant data leak risks, bloated table partitions, and disastrous noisy-neighbor incidents during heavy reporting runs. In 2026, the solution for multi-tenant B2B platforms is not adding another layer of caching. It is breaking up the monolith into tens of thousands of lightweight, isolated, per-tenant SQLite databases executed directly at the edge. ### The Architecture of the Micro-Tenant Database In a SaaS application, a customer in Frankfurt does not care about data belonging to a customer in Singapore. There is no business logic that requires joining their accounts in an ad-hoc SQL query. By segmenting data boundaries along natural tenant lines, you can deploy a dedicated SQLite database for each organization. * **Zero cold-starts**: SQLite engines compiled into WebAssembly or embedded directly into edge V8 isolates mount in under 5 milliseconds. * **Deterministic isolation**: Tenant data breaches are physically impossible at the storage layer; customer A cannot write an SQL query that escapes into customer B’s file handle. * **Local execution speed**: With the database living inside the same memory address space as your application handler, queries run in microseconds, completely removing the concept of network transport latency from your ORM calls. ### Synchronizing Writes to Long-Term Object Storage Running SQLite at the edge creates an obvious challenge: SQLite is inherently single-writer, and edge isolates are stateless. You cannot rely on a local NVMe drive on a serverless node because that node may spin down within seconds. To resolve this, we leverage stateful edge primitives (like Cloudflare Durable Objects or Fly.io micro-machines) paired with atomic WAL (Write-Ahead Log) streaming to globally distributed object storage (S3/R2). The Durable Object serves as the coordination leader for a specific tenant, guaranteeing single-writer consistency while streaming compressed WAL frames asynchronously to durable storage. Here is how an edge handler routes incoming HTTP mutations directly to an isolated, per-tenant Durable SQLite instance: ```typescript export interface Env { TENANT_STORAGE: DurableObjectNamespace; } export default { async fetch(request: Request, env: Env): Promise<Response> { const tenantId = request.headers.get('X-Tenant-ID'); if (!tenantId) { return new Response('Missing Tenant Identifier', { status: 400 }); } // Route request directly to the tenant-specific isolated instance const id = env.TENANT_STORAGE.idFromName(tenantId); const stub = env.TENANT_STORAGE.get(id); return stub.fetch(request); }, }; ``` ### Eliminating the N+1 Query Penalty The most liberating aspect of running an embedded database inside your compute runtime is the death of the N+1 query problem. Over traditional networks, executing 100 sequential SQL queries inside a loop creates an unacceptable 3-second latency penalty due to socket round-trips. When your SQLite database is embedded inside the compute isolate: * A sequence of 100 queries executes in under 2 milliseconds. * You can ditch bloated GraphQL caching layers and complex aggregate join queries in favor of readable, sequential imperative code. * Data migrations become trivial: instead of executing a terrifying schema migration across a 2-terabyte table while praying the database does not lock up, you run zero-downtime, progressive schema migrations tenant-by-tenant as each individual tenant boots their isolate. ### The Operational Reality Decentralizing your database layer shifts complexity from database administration to routing infrastructure. You need robust edge routing, automated backup snapshots, and a solid tenant provisioning layer. But in exchange, you eliminate your single point of failure, permanently solve tenant data isolation, and deliver database response times that feel practically instantaneous.
sqlite
edge-computing
web-development
databases
Share X LinkedIn

What clients say

Real reviews from founders and teams we've shipped with.

5.0 · 6 reviews
"Hashim rebuilt our checkout in a weekend and conversions jumped 34% the following week. Unreal."
Ethan R.
Head of Growth, Shopstack
"The most senior engineer we've worked with. Understands business, not just code."
Sara L.
CEO, Best Forex Trading Broker
"Delivered a scalable app directory that keeps growing. Best engineering partner we've had."
Priya V.
Founder, AppsWant
"Zero flaky tests after Hashim rewrote our Playwright suite. CI is finally green and trustworthy."
Ravi P.
QA Lead, Trustflow
"Broker directory that ranks and converts. The SEO foundations alone were worth it."
Rohit D.
Founder, Stock Broker of India
"From concept to launch in weeks. The browser project set a new bar for our team."
Vikram J.
Founder, Finup Browser