Swytch vs SQLite
SQLite is the most widely deployed database in history. It runs in your phone, your browser, your car, your fridge. It’s in every Mac and every iPhone and the black box of every airplane that’s flown since about 2011. It’s correct, fast, ridiculously well-tested, and free.
If you’re reading this page, you probably already know all that. The question you’re actually asking is: why would I ever use anything else?
Fair question. Let’s answer it honestly.
Swytch is, in one sentence, SQLite plus a network. The SQL engine inside Swytch is SQLite — specifically
zombiezen.com/go/sqlite, embedded in the Swytch binary. Your queries are parsed by SQLite, executed by SQLite, and
return results shaped by SQLite. If a query works in plain SQLite, it works in Swytch. If it doesn’t work in SQLite — a
Postgres SELECT ... FOR UPDATE, for instance — it doesn’t work in Swytch either.
What Swytch adds is everything around the engine. Replication. Multi-node operation. A Postgres wire protocol so your existing drivers and tools connect. Active-active writes across regions. A causal DAG underneath it all that handles network partitions without data loss.
A Swytch binary runs in one mode — SQL or Redis — chosen at startup. If you need both faces on the same data, you run two binaries that share the same underlying DAG. For this page, assume SQL mode. Everything about the SQL dialect, wire protocol, and replication model below is what you get when you start Swytch in SQL mode.
That’s the pitch. Now let’s talk about when it’s the right call, and when SQLite alone is still the right call.
| SQLite | Swytch | |
|---|---|---|
| Deployment | Embedded library, one file | Standalone binary, one or many nodes |
| Nodes | One | One or more, active-active |
| Writers | One at a time (file lock) | Every node, concurrently |
| Network needed? | No | Yes, between nodes |
| Wire protocol | None (in-process API) | PostgreSQL wire (SQL mode) or Redis RESP (Redis mode), per binary |
| SQL dialect | SQLite | SQLite |
| Replication | None (use Litestream/LiteFS) | Synchronous to interested nodes |
| Partition handling | N/A (single node) | First-class, holographic divergence |
| Durability | Disk, locally | In-memory across subscribed nodes by default; disk via Swytch Cloud |
| Write latency | ~microseconds (local disk) | ~1 RTT to furthest subscriber |
| Read latency | ~microseconds (local disk) | ~microseconds (local node) |
| Operational surface | Approximately zero | One binary, one config |
| License | Public domain | AGPL (open source) + commercial |
SQLite wins on simplicity. Swytch wins when one node isn’t enough.
If any of these describe your situation, the answer is SQLite. Don’t overthink it.
Single-process application. A CLI tool, a desktop app, a mobile app, a single-server web service that doesn’t need to scale horizontally. SQLite is faster than any networked database because there’s no network. The API is in-process. A query is a function call.
Read-heavy workload on one machine. A documentation site, a static data lookup, an analytics read-replica. SQLite will serve you tens of thousands of reads per second on cheap hardware and never complain. Adding a network only makes it slower.
Your data fits on one machine and always will. SQLite happily handles hundreds of gigabytes. If your working set fits in RAM and your data fits on SSD, and you don’t foresee that changing, single-node SQLite is probably the simplest, fastest, most reliable answer available.
You want zero operational surface. SQLite has no daemon. No port. No config file. No backup tooling beyond cp.
If “I don’t want to run a database” is the constraint, Swytch doesn’t meet it — it’s still a process you have to run,
even if that process is tiny.
You’re using SQLite as a file format. Game saves, application state, exported reports. SQLite is a brilliant file format that happens to support SQL. Swytch isn’t trying to replace this use case and never will.
For any of the above, the honest answer is: use SQLite. The Swytch pitch doesn’t apply.
The moment you outgrow SQLite isn’t when your data gets bigger. It’s when you need a second node.
The common triggers:
Multiple application instances. You’ve gone from one server to two. Now they need to see the same data. With SQLite, your options are: put the file on shared storage (slow and fragile), use Litestream to stream WAL to S3 (fine for backup, doesn’t help with live reads), or swap in LiteFS (better, but introduces a single-writer primary and FUSE). With Swytch, both application instances connect to their local Swytch node. Each node subscribes to the tables its application actually queries, and a write commits synchronously to the nodes subscribed to that table. No primary. Either node can write. You pay the RTT only between nodes that care about the same table.
Multi-region. You have users in both Europe and the US. Latency from one to the other is 100ms. Running SQLite means picking a region and accepting that half your users are always slow. Running LiteFS means picking a primary region and accepting that all writes are slow for the other region. Running Swytch means each region writes locally — at whatever latency its subscribers impose. If a table only has subscribers in one region, writes to that table are region-local and fast. If a table has subscribers in both regions, writes pay the cross-region RTT, but only for that table. You pay the lag you actually need, not a blanket cost on every write.
Devices that go offline. A POS terminal at a venue that loses uplink. An oil platform that drops connectivity during a storm. A truck moving through a tunnel. With plain SQLite, you have a local database and a synchronization problem you have to solve yourself — and you will solve it wrong at least twice before you get it right. With Swytch, offline operation is the default mode; reconciliation on reconnect is the database’s job, not yours.
Writes from multiple places. SQLite’s single-writer lock is famously fine for most workloads, right up until it
isn’t. If you have genuinely concurrent writers — say, ten worker processes all accepting API requests — you’ll
eventually hit SQLITE_BUSY. You can paper over it with retry loops and WAL mode and careful transaction scoping, and
for many workloads that’s enough. But if you find yourself engineering around the lock, you’ve outgrown SQLite. Swytch
accepts writes from every node concurrently, and resolves any conflicts by last-writer-wins — using the causal DAG’s
ordering, not a wall clock.
You care about durability beyond the disk. This one cuts both ways, so let’s be specific. SQLite’s durability story is “the disk didn’t lie to you.” If the machine dies, your data is on that disk and nowhere else. Swytch, out of the box, is the opposite: data lives in memory across subscribed nodes. If a node dies, the data is still on the other subscribers. If every subscriber for a given table dies at the same time, that data is gone. Swytch Cloud, the control plane, adds distributed durable storage on top — writes land on disk, survive full-cluster restart, and the full causal history is preserved.
So: SQLite’s durability is single-node and disk-based. Swytch’s default durability is multi-node and memory-based. Swytch plus Cloud gets you both.
If you’re nodding at any of these, keep reading. If you’re not, close this tab and use SQLite.
This is the section every comparison page should have and most don’t. Here’s what you’re trading.
Speed on single-node writes. A local SQLite write, with PRAGMA synchronous=NORMAL and WAL mode, is somewhere in
the microsecond range. A Swytch write commits in one RTT to the furthest subscriber — sub-millisecond if the subscribers
are all on the same machine, single-digit milliseconds within a region, tens of milliseconds cross-region. If your
latency budget cares about the difference between 50 microseconds and 2 milliseconds, SQLite is faster. This is physics,
not engineering.
Zero-dependency deployment. SQLite has no deployment. It’s a library you link against. Swytch is a binary you run. It’s a small, friendly binary — one file, one command, no config required to start — but it is a process. You have to start it, stop it, monitor it, and keep it running. For many projects this is a rounding error. For some, it’s the deal-breaker.
The ecosystem. SQLite has been around since 2000 and has tooling for everything. Every language has bindings. Every ORM supports it. Every IDE has a GUI for it. Swytch is 1.0-beta1. You get Postgres and Redis wire protocol compatibility, which buys you most of the ecosystem by proxy — but “most” isn’t “all,” and you will occasionally hit a tool that expects something Swytch doesn’t yet implement. We’re catching up quickly. We’re not caught up yet.
In-process speed. SQLite is embedded. A query is a function call. Swytch is accessed over a socket, even when the socket is on the same machine. For tight inner loops doing millions of small queries, in-process SQLite will always be faster. If you can tolerate a Unix domain socket, the penalty is small. If you can’t, SQLite wins.
The “it’s just a file” property. Your SQLite database is a file you can scp, attach to a bug report, version in
git (for small enough databases), open in any SQLite browser on any machine. Swytch data doesn’t live in a file you can
hand to someone — it lives in a cluster. You can export it and you can snapshot it, but it isn’t portable the way a
SQLite file is portable. Out of the box, that’s a real loss for debugging and data archaeology.
With Swytch Cloud, the story flips. Cloud keeps the full causal history of every row — not just the current state, but every change, the transaction that made it, and the related writes that happened around it. A SQLite file tells you what the data looks like right now. Cloud tells you how it got there. For debugging, that’s a strict upgrade — you stop guessing at the state machine and start reading its transcript.
PRAGMA tuning. SQLite has roughly thirty knobs you can turn to squeeze out performance or change behavior. Swytch
inherits the SQL engine but not the full PRAGMA surface — some pragmas are meaningless in a distributed context (
journal_mode, locking_mode) and some aren’t yet supported. If your current SQLite setup leans heavily on pragmas,
check the SQL Dialect page before assuming it all transfers.
Memory-bounded operation. SQLite will happily serve a 200GB database off an SSD with 4GB of RAM. Swytch, without Swytch Cloud, keeps data in memory across the nodes subscribed to each table. Your cluster’s total addressable storage is bounded by the memory of your nodes — and for any given table, by the memory of the nodes that care about it. For small-to-medium datasets this is a non-issue, and the in-memory speed is a feature. For large datasets, you either scale the cluster wider, subscribe more selectively, or run Swytch Cloud for disk-backed storage. This is the single largest operational difference from SQLite, and worth sizing for before you start.
Partition-aware sharding. SQLite has no concept of partitions because there’s nothing to partition. Swytch, being multi-node, does. Writes during a partition aren’t lost — the full causal history is preserved — but if both sides wrote to the same table, the late arrival wins, and that’s rarely what your business wants deciding for you. The honest way to run active-active is to design your write paths so partitioned nodes don’t overlap: shard by region, tenant, device, whatever fits your domain. This is real engineering work that SQLite doesn’t ask of you, and Swytch does.
Honest summary: Swytch costs you simplicity, raw single-node speed, and some ecosystem maturity, in exchange for operating across more than one machine. Whether that trade makes sense is entirely about whether you need more than one machine.
Everything that made SQLite the right call in the first place, mostly:
- The SQL dialect. Same parser, same builtins, same quirks.
json_extract,strftime,GLOB,RETURNING— all there. - The reliability story. SQLite’s test suite is the most thorough in the industry. Swytch runs it as part of CI. The engine underneath Swytch is the same engine you already trust.
- The mental model. Tables, rows, indexes, transactions. If you know how to reason about SQLite, you know how to reason about Swytch’s SQL layer.
- Dynamic typing. SQLite’s type affinity rules come along for the ride. If you relied on “store anything in any column” behavior, you still can.
- Zero-config bring-up. Starting a Swytch node in SQL mode is about as close to “it just runs” as a server process gets. No storage engine to choose, no replication topology to wire up, no user accounts to create before your first query.
If you’ve decided to try it, the migration is about as smooth as this kind of thing gets. A rough sketch:
- Your existing SQLite schema — CREATE TABLE, indexes, views — will mostly port directly. Swytch speaks SQLite, so the DDL you already have is the DDL you’ll use.
- Your application code changes depending on how it talks to SQLite. If you’re using a Postgres driver against Swytch, you’ll swap out your SQLite driver for a Postgres one. The SQL strings mostly don’t change.
- If you lean on PRAGMAs or SQLite-specific C-level extensions (FTS5, R-Tree, custom virtual tables), check the SQL Dialect page. Most common extensions are supported; some aren’t yet.
- Data migration is a dump and restore. Export from SQLite (
.dump), pipe into Swytch via psql. For larger databases, there are faster paths — the Migration Guide covers those.
The deeper you are in SQLite-specific internals, the more work there is. For most applications, migration is an afternoon.
SQLite and Swytch aren’t really competitors. SQLite is a library for talking to a database file. Swytch is a server that speaks distributed SQL using SQLite as its engine, with data living in memory across a cluster by default — and on disk via Swytch Cloud if you want that. If one node is enough, SQLite is almost always the right call — it’s simpler, faster in-process, disk-backed by default, and has a quarter-century of battle-testing. If one node isn’t enough — because you have multiple app instances, multiple regions, unreliable networks, or writes coming from more places than SQLite’s single-writer lock can handle — Swytch is the upgrade path without giving up the parts of SQLite you actually liked.
Use the right tool for the job. We’re a fan of the other tool, too.