Skip to main content
Back to Blog
Privacy February 11, 2026 · Steven Melendez

Your Data Should Be Yours

Why local-first architecture isn't a compromise — it's the point.


There's a default assumption in modern software that your data lives on someone else's computer. Your notes sit in a database behind an API you don't control. Your contacts are indexed by an ad platform. Your calendar events pass through servers that could, technically, read every entry. We've accepted this as the cost of convenience — sync across devices, search that works, collaboration that doesn't require emailing files back and forth.

But "technically could" has a habit of becoming "routinely does." Data breaches aren't edge cases anymore, they're quarterly news. And the response from most software companies is the same: better security on their servers, more compliance certifications, longer privacy policies. The implicit message is always trust us — we'll protect your data on our infrastructure, behind our access controls, subject to our policies.

There's another way to build software. One where the trust model isn't "trust the vendor" but "trust the math."

What If There Were No Servers to Breach?

Consider a different architecture. Your data lives on your machine, in local databases. When it needs to sync between your laptop and your phone, the two devices find each other — either directly on the same network, or through a relay that exists only to help them connect, the way a phone switchboard connects two callers without listening to the conversation. The relay is stateless. It doesn't store anything. If it went offline tomorrow, your data would still be on your devices, exactly where you left it.

This is how peer-to-peer sync works in practice. Devices discover each other via mDNS on local networks or through a Kademlia DHT for wide-area connections. When a direct connection isn't possible (NAT traversal fails, different networks, firewalls), traffic routes through a relay — but the relay is just a dumb pipe. It forwards encrypted bytes between peers. It has no keys, no user accounts, no database. The only thing it knows is that two peer IDs want to talk.

The relay's entire codebase fits in a single file. It runs three protocols: relay for NAT traversal, Kademlia for peer discovery, and identify for protocol negotiation. That's it. No user table. No session store. No analytics. No logs of who synced what. The only state it holds is a QUIC connection timeout counter.

Encryption That Doesn't Require Trust

When data is encrypted at rest, the question is always: who holds the keys?

A two-tier key system handles this cleanly. A master key is derived from your password using Argon2id — a memory-hard key derivation function designed to resist brute-force attacks. This master key is never stored anywhere. It exists in memory while the app is unlocked and is zeroized when you lock it. Each entity (a note, a contact, a task) gets its own random key, which is encrypted with the master key and stored alongside the ciphertext.

This design has practical consequences. Changing your password doesn't require re-encrypting every piece of data — only the entity keys get re-wrapped with the new master key. Sharing a single entity means sharing just that entity's key, not the master key. And if one entity key is somehow compromised, it doesn't affect any other entity. Forward secrecy at the entity level.

The encryption uses ChaCha20-Poly1305 — an authenticated cipher that provides both confidentiality and integrity. If someone tampers with the ciphertext, decryption fails entirely rather than producing corrupted output. There's no mode where the system silently returns bad data.

Blob storage (files, images, attachments) follows the same pattern. Content hashes are computed on plaintext before encryption so deduplication works correctly across password changes. The hash of a file is a property of the file, not of how it's stored.

Sync Without a Central Authority

The hard problem with local-first software is sync. Two devices edit the same note offline. When they reconnect, whose version wins?

The answer is: both do. Conflict-free Replicated Data Types (CRDTs) are data structures that can be edited concurrently on multiple devices and merged deterministically without conflicts. There's no "last write wins" coin flip. The merge is mathematically guaranteed to converge to the same state regardless of the order events arrive.

The sync process works in phases: discovery, handshake, state exchange (comparing vector clocks to determine what each peer is missing), event sync in batches, and CRDT merge on the receiving end. The same protocol works for two devices or twenty. Gossip-based selective sync means not every peer needs to talk to every other peer — convergence is transitive. If A syncs with B, and B syncs with C, then A and C converge even though they never directly connected.

This also means there's no central sync server that could be subpoenaed, hacked, or shut down. The sync topology is whatever your devices make it. Two laptops on the same WiFi network sync directly. A phone on cellular data reaches through the relay. The data never sits at rest on any machine you don't own.

The Trade-Off That Isn't

The conventional wisdom is that local-first means giving up features. No real-time collaboration. No search across devices. No dashboard that works without opening the app.

But that framing confuses "server-dependent" with "capable." A local DuckDB database can run the same SQL queries as a cloud Postgres instance — GROUP BY, JOIN, window functions, CTEs, aggregations. Full-text search works on local indexed fields. Charts and visualizations render from local data. The features don't disappear when you remove the server; they just run on your hardware instead of someone else's.

The actual trade-off is a development one. Building local-first is harder than building server-first. Every feature that would normally be a REST endpoint and a database query becomes an FFI boundary, a CRDT merge strategy, and an encryption pass. The architecture is more complex because the trust model is more honest — it doesn't hand-wave away the question of who can read your data by pointing at a compliance checklist.

Why It Matters

Privacy isn't a feature you bolt on. It's an architectural decision you make at the foundation, and every layer built on top either preserves it or erodes it. Encrypting data on a server you control is better than not encrypting it, but it still means someone — you, your vendor, an employee, a government order — can decrypt it. Encrypting data on a machine the user controls, with keys derived from a password only they know, means nobody else can. Not even the developer who built the system.

That's not a privacy policy. It's a mathematical guarantee. And it's the kind of guarantee that should be the default, not the exception.