A developer walks into a bar. He orders a local-first, end-to-end encrypted chat application built on an embedded vector database and a decades-old cryptographic library. The bartender says: “Why?” The answer, it turns out, is more instructive than the punchline.
Justin R. Miller, a software engineer and technical writer, recently published a detailed walkthrough of building exactly that — a fully end-to-end encrypted (E2E) chat application using LanceDB, an embedded vector database, and libsodium, the widely trusted cryptographic library. The project, documented on Miller’s personal site, isn’t a toy demo. It’s a provocation — a proof of concept that challenges assumptions about where encryption should live, what databases should do, and how much infrastructure modern messaging actually requires.
The timing isn’t accidental. Encrypted messaging is under political and technical pressure simultaneously. Governments from the EU to Australia continue pushing for backdoor access to encrypted communications. Meanwhile, the AI boom has made vector databases — originally designed for similarity search over embeddings — one of the hottest categories in data infrastructure. Miller’s project sits at the intersection of both trends, and it raises questions that matter far beyond a single GitHub repo.
Why an Embedded Database Changes the Trust Model
Most encrypted chat systems — Signal, WhatsApp, iMessage — rely on centralized servers to route messages, even if the server can’t read them. The server stores ciphertext. It handles key exchange metadata. It knows who’s talking to whom, and when. The encryption protects content, not context.
Miller’s architecture takes a different approach. LanceDB is an embedded database, meaning it runs inside the application process itself. There’s no separate database server. No network hop to a managed cloud instance. The data lives locally, on disk, in the Apache Arrow columnar format that LanceDB uses natively. This matters for encryption because it collapses the trust boundary. When your database is embedded, you don’t need to trust a database operator. You don’t need to worry about a cloud provider being compelled to hand over ciphertext. The encrypted data never leaves the machine unless the application explicitly sends it somewhere.
This is a meaningful architectural distinction. It’s the difference between encrypting data before sending it to someone else’s computer and never sending it to someone else’s computer at all.
LanceDB, developed by the team at LanceDB Inc. (formerly Eto Labs), has been gaining traction primarily in the AI and machine learning space. Its core use case is storing and searching vector embeddings — the high-dimensional numerical representations that power semantic search, retrieval-augmented generation (RAG), and recommendation systems. But Miller’s project demonstrates that the database’s embedded nature and flexible schema make it suitable for workloads that have nothing to do with AI. In this case, it’s functioning as a local-first message store with structured metadata and encrypted payloads.
The choice is unconventional. SQLite would be the obvious pick for an embedded database powering a chat app. But Miller’s selection of LanceDB appears deliberate — partly to explore the tool’s versatility, and partly because its columnar storage and native support for complex data types (including binary blobs for ciphertext) make it a surprisingly natural fit.
On the cryptographic side, libsodium does the heavy lifting. Libsodium is a fork of Daniel J. Bernstein’s NaCl (“salt”) library, and it’s become the de facto standard for developers who want strong cryptography without the footguns that come with lower-level libraries like OpenSSL. It provides authenticated encryption (XSalsa20-Poly1305), key exchange (X25519), and hashing — all with an API designed to be hard to misuse.
Miller’s implementation uses libsodium’s public-key authenticated encryption box. Each user generates a keypair. To send a message, the sender encrypts using the recipient’s public key and their own secret key. The recipient decrypts using their own secret key and the sender’s public key. This provides both confidentiality and authentication in a single operation. No certificates. No certificate authorities. No TLS negotiation. Just math.
The messages, once encrypted, are stored as binary data in LanceDB. The database indexes metadata — timestamps, sender identifiers, conversation IDs — but the message content remains opaque ciphertext that only the intended recipient can decrypt. Even if someone gains access to the database file on disk, they get nothing useful without the private keys.
Here’s where it gets interesting from an infrastructure perspective. Because LanceDB is embedded, the entire system — encryption, storage, retrieval, decryption — runs in a single process. There’s no network attack surface for the data-at-rest layer. There’s no connection string to misconfigure. There’s no database credential to leak. The security model is radically simplified compared to a typical architecture where an application server talks to a managed PostgreSQL instance over TLS, with encrypted columns or transparent data encryption layered on top.
Simplicity in security architecture is not a luxury. It’s a survival strategy. Every additional component in a system is another thing that can be misconfigured, compromised, or compelled.
The Broader Context: Local-First Software and the Encryption Wars, Redux
Miller’s project arrives during a period of renewed tension between privacy advocates and government regulators. In the European Union, the proposed “Chat Control” regulation would require messaging platforms to scan messages for child sexual abuse material — a requirement that is technically incompatible with end-to-end encryption as currently implemented. The UK’s Online Safety Act contains similar provisions. In the United States, the FBI and DOJ have repeatedly called for “responsible encryption” that allows lawful access, a concept that cryptographers have consistently argued is a contradiction in terms.
Against this backdrop, local-first architectures represent a technical end-run around regulatory pressure on centralized platforms. If there’s no server, there’s no server to serve with a warrant. If the database is embedded in the user’s device, compelling access means compelling the user — a much higher legal bar in most jurisdictions, and a practically harder problem.
This isn’t hypothetical. The local-first software movement, championed by researchers like Martin Kleppmann at the University of Cambridge and articulated in the influential Ink & Switch essay on local-first software, has been gaining momentum for years. The core principles: data lives on the user’s device, the application works offline, collaboration happens through synchronization protocols rather than centralized servers, and the user retains ownership and control of their data.
Miller’s chat application embodies these principles, even if it’s a proof of concept rather than a production system. Messages are encrypted locally, stored locally, and decrypted locally. The hard part — and Miller acknowledges this — is the transport layer. How do encrypted messages get from one user’s local LanceDB instance to another’s? The blog post focuses on the encryption and storage layers, leaving the networking question open. In a production system, you’d need some mechanism for message delivery: a relay server, a peer-to-peer protocol, or something like the Matrix protocol’s federated architecture.
But that’s precisely the point of the exercise. By decomposing the problem — separating encryption and storage from transport — Miller demonstrates that the hardest parts of secure messaging aren’t actually that hard when you remove the server from the trust model. The hard part is the plumbing, not the cryptography.
And the cryptography, thanks to libsodium, really isn’t hard. The library’s API is famously minimal. Encrypting a message is a single function call: crypto_box_easy(). Generating a keypair is a single function call: crypto_box_keypair(). The library handles nonce generation, authentication tags, and constant-time comparisons internally. A developer who can read documentation can implement authenticated public-key encryption in an afternoon. Miller’s walkthrough confirms this — the encryption layer is arguably the simplest part of the entire application.
This accessibility matters. For years, the conventional wisdom has been that “you should never roll your own crypto.” That advice remains sound when it comes to designing cryptographic primitives. But libsodium has shifted the practical reality: you don’t need to roll your own crypto. You need to call the right functions in the right order. The bar for building encrypted applications has dropped dramatically, and projects like Miller’s make that tangible.
The vector database angle adds another dimension. LanceDB’s architecture — built on Lance, an open columnar data format designed for ML workloads — means that the same database storing encrypted chat messages could, in theory, also store vector embeddings for semantic search over those messages. Imagine a chat application where you can search your message history by meaning rather than keyword, with all search happening locally, over encrypted-then-decrypted data. No cloud. No indexing service. No third party ever sees your messages or your queries.
This convergence of local AI inference and local-first encrypted storage is a frontier that several startups and open-source projects are beginning to explore. Apple’s recent push toward on-device AI processing with Apple Intelligence, and its introduction of Private Cloud Compute for tasks that exceed on-device capability, reflects a similar philosophical direction: keep data local when possible, and when you can’t, minimize trust in the remote infrastructure.
What This Means for Developers and Architects
Miller’s project is a proof of concept. It’s not Signal. It’s not pretending to be. But it illustrates several principles that are directly applicable to production systems.
First: embedded databases deserve more consideration for security-sensitive applications. The reflexive reach for PostgreSQL or MySQL introduces network attack surface, credential management complexity, and operational overhead that may be unnecessary for applications where data is inherently per-user or per-device. SQLite has long been the workhorse here, but LanceDB, DuckDB, and other modern embedded databases offer capabilities — columnar storage, complex types, vector search — that SQLite doesn’t.
Second: libsodium has made application-layer encryption accessible enough that there’s diminishing excuse for not encrypting sensitive data before it hits any storage layer. The library is available in virtually every programming language. The API is well-documented and hard to misuse. The performance overhead is negligible for message-sized payloads.
Third: the local-first architecture pattern is increasingly viable for a wider range of applications than its proponents initially envisioned. Sync protocols like CRDTs (conflict-free replicated data types) and projects like Automerge and Yjs have matured to the point where multi-device, multi-user collaboration is possible without a centralized server acting as the source of truth. When you combine local-first sync with end-to-end encryption and an embedded database, you get an application architecture that is private by construction, not by policy.
So what’s missing? Plenty. Key management in the real world is brutally hard. Miller’s demo assumes users can exchange public keys, but in practice, key discovery, key verification, and key rotation are unsolved problems at scale — or rather, they’re solved only by centralized key servers, which reintroduce the trust assumptions that local-first architectures are trying to eliminate. The Signal Protocol’s approach — using a central key server but verifying keys out-of-band via safety numbers — is a pragmatic compromise, but it’s a compromise nonetheless.
Group messaging adds another layer of complexity. Libsodium’s crypto_box is designed for two-party communication. Group chats require either encrypting each message N times (once per recipient) or using a group key management protocol like Signal’s Sender Keys or the IETF’s Messaging Layer Security (MLS) standard. Miller’s demo doesn’t address this, and it’s where most real-world encrypted messaging systems accumulate their complexity.
There’s also the question of metadata. Even in a local-first architecture, if messages are transmitted over the internet, network-level metadata — IP addresses, timing, message sizes — can reveal communication patterns. Protecting metadata requires additional techniques: onion routing, mixnets, or protocols like those used by the Tor network. This is a fundamentally harder problem than content encryption, and no amount of clever database selection solves it.
But none of these limitations diminish the core insight of Miller’s project. The tools for building encrypted, local-first applications are better than they’ve ever been. The embedded database removes the server from the storage trust model. The cryptographic library removes the PhD from the encryption trust model. What remains is engineering — hard, detailed, important engineering — but not mystery.
For an industry that has spent two decades building everything on top of centralized cloud infrastructure, the reminder is bracing. Not every application needs a server. Not every database needs a network connection. And not every message needs to pass through someone else’s hands.
Sometimes the most secure architecture is the simplest one. An embedded database. A proven crypto library. And a message that only two people can read.


WebProNews is an iEntry Publication