For twenty years the default answer to “where does the data live?” was a database server somewhere else. You opened a connection, sent a query over the network, and waited. That model still runs most of the world’s business software. But at the edge, on phones, in sensors, inside a browser tab or a serverless function a few milliseconds from the user, the answer is shifting. The data lives in a file, and the database is a library linked into the program that reads it.
SQLite has worked this way since 2000, and it never stopped shipping. Version 3.54.1 came out on October 16, 2026. DuckDB, the analytical cousin, shipped its 2.0.0 LTS release on October 21, built from close to 20,000 commits since 1.5. Turso is rewriting SQLite in Rust with concurrent writes. Cloudflare gives every SQLite-backed Durable Object its own database and builds D1 on the same foundation. The small, in-process database has gone from embedded curiosity to the storage layer people pick on purpose.
Why? Mostly physics.
The network hop is the expensive part
A query against a local SQLite file is a function call. Reading a row by key takes microseconds. The same read against a managed Postgres instance in another region goes through a TCP connection, TLS, a connection pool and a round trip that can easily cost 50 to 100 milliseconds. On a web page that fires a dozen queries, that gap is the difference between instant and sluggish.
Edge platforms make the problem worse before they make it better. If your code runs in 300 cities and your database sits in one, every request still crosses an ocean to get its data. Moving compute to the edge without moving data with it just relocates the wait. Cloudflare’s answer was to put the database next to the code. A SQLite-backed Durable Object keeps its own private database of up to 10 GB on the Workers Paid plan, stored on the same machine that runs the object, so reads are local disk reads. D1, Cloudflare’s managed SQLite service, caps each database at 10 GB as well, allows up to 50,000 databases per paid account, and now supports read replicas, each one its own Durable Object.
That cap tells you the design philosophy. Nobody is trying to build one giant database. The bet is on many small ones: a database per customer, per document, per chat room, per device. That pattern fits a single-file engine perfectly and fits a big shared server badly.
Offline first, sync later
The second reason is that the edge is often disconnected. A delivery driver’s phone loses signal in a parking garage. A soil sensor on a farm talks to its gateway twice a day. A factory line keeps running when the plant’s uplink goes down. Software in these places has to accept writes locally and reconcile them later, and an embedded database is the obvious place to keep them.
This is where most of the interesting work is happening. Turso has offline sync in beta, with local writes pushed to the cloud and remote changes pulled down when the connection returns. In August 2026 it opened an early preview of concurrent writes on Turso Cloud, using BEGIN CONCURRENT and an MVCC design adapted from Microsoft’s Hekaton, so writers that touch different rows don’t queue behind one lock. The open-source Turso engine, a ground-up Rust rewrite of SQLite, had shipped MVCC a couple of months before that.
The browser joined the party too. SQLite has an official WebAssembly build that can persist to the Origin Private File System, and DuckDB runs in WASM as well. A web app can carry a real SQL engine and query megabytes of local data without a server round trip at all. For dashboards, note-taking apps and anything that has to work on a train, that changes the architecture.
Size matters too, at the far end of the edge. A microcontroller with a few hundred kilobytes of flash can’t host Postgres. It can host a key-value store. LMDB, a memory-mapped B-tree from the OpenLDAP project, has been the quiet workhorse here for years: tiny and crash-safe by design, with very fast reads. RocksDB, Meta’s log-structured store, sits at the other end of the scale, embedded inside larger systems that need heavy write throughput. Both prove the same point. You don’t need a server process to get durable, transactional storage. You need a good file format and careful code around fsync.
DuckDB pushes the in-process idea into analytics. It reads Parquet and CSV directly, runs columnar queries on a laptop that once needed a warehouse, and in 2.0 added asynchronous I/O for remote and object-storage reads. It also polished Quack, its client-server protocol, which is a tell. Even the in-process champions are adding a server mode for the cases where one process isn’t enough.
The honest trade-offs
None of this makes the embedded database a universal answer, and pretending otherwise burns teams.
Concurrency is the first limit. SQLite in WAL mode lets many readers run alongside one writer. One. If your workload has many processes writing at once, they queue, and under load they time out. Turso’s MVCC work exists precisely because this is the most common complaint. It’s promising; it is also new.
Write scaling is the second. A single file on a single machine scales up, not out. Cloudflare’s 10 GB ceiling per database is a hard limit, and the documentation says it can’t be raised. The answer is sharding by design (one database per tenant), which is elegant when your data splits cleanly and painful when it doesn’t. Cross-tenant reporting means pulling data somewhere else.
Replication is the third, and the hardest. Read replicas are easy to bolt on. Multi-writer sync is not. Two devices editing the same record offline will conflict, and someone has to decide who wins: last-writer-wins, CRDTs, or application logic. Turso’s own offline sync beta shipped conflict detection before conflict resolution, which is a candid sign of how hard this is. Anyone selling painless offline sync for arbitrary SQL is skipping a chapter.
And there’s operations. A server database gives you one place to back up, monitor and patch. Ten thousand embedded databases spread across devices give you ten thousand places. The tooling is getting better, but it is still younger than the Postgres ecosystem by decades.
A few small projects worth watching
The space is wide open for smaller engines that pick one hard problem and work on it. Three open-source projects take different cuts at it.
AltSql targets IoT. It puts key-value access and SQL on the same records from a microcontroller to a gateway, with the device side at about 15 KB. It’s in alpha, tested in simulation, including 400,000 simulated power cuts without losing saved data, and compiled for a Cortex-M4 but not yet run on real chips. We covered its device-to-gateway sync idea in more detail here.
KvSQL is a Rust engine with no dependencies beyond the standard library. Key lookups read rows straight from the B-tree, SQL queries read the same rows, and both share one file and one transaction. It ships as an embedded engine plus a small HTTP server, kvsqld. Version 0.1.0 came out on October 22, so it’s early.
HyperCrux goes for breadth: SQL, key-value, graph links and vector search over the same records in one SQLite file, embedded in Go or run as a single binary. It’s at version 0.2 under Apache 2.0, with a pure Go beta engine in pre-release.
All three are young, and their benchmarks are self-reported. They’re interesting because they share the instinct driving the bigger names: keep the data next to the code, in one file, and make the different ways of reading it agree.
That instinct is winning the edge. The server isn’t going away. It’s just no longer the first place the data goes.