In the context of web, most engineers laugh when you mention "sqlite in production". After all, it’s
known as a lightweight, single-file database - not the backbone of a SaaS app.
But for the past year, our team has been running a product with 5B reads and 500k writes per month on libsql (a fork of sqlite).
Here’s what we learned — the good, the bad, and the panic-inducing wal
surprises.
Of course, running plain sqlite in production — that would’ve been painful almost immediately. Without fine-tuning or some management layer, you’ll hit concurrency errors and bottlenecks right away. In practice, if you want to use sqlite beyond toy projects, you’ll end up looking at forks and wrappers that promise to make it production-ready. Here are the ones I’ve come across, along with my thoughts on each.
libsql
The key idea of this project is to have a fully compatible fork of the original
sqlite
. Why? There are several reasons:
- sqlite is open for reading, but closed for contributions.
- modern apps need certain configurations out of the box. Hello
wal
mode. - full compatibility with sqlite.
You can check out this section for details.
Well, having a great ready-to-go setup from Turso, our team uses this solution. It works just fine, except for some pitfalls...
rqlite
Another mature solution built upon sqlite.
Here we have a slightly different approach: instead of developing a fork
of sqlite, they went with a wrapper.
In stark contrast, rqlite does not modify the sqlite engine. Instead, it wraps the standard, unmodified sqlite library with an external layer, written in Go, that provides distributed capabilities. This layer implements the Raft consensus algorithm to create a replicated, consistent log of SQL statements that are then applied to each node's local sqlite database file.
Does it sound impressive? Obviously. Do I use it? Hmm, not really...
Here’s the explanation: the engine and idea sound very encouraging and this project
definitely has a lot of advantages. However, without proper advertising of
the product, many will just miss the most fascinating parts. That was
my case as well. I just didn't find any easily searchable examples of
rqlite + ORM like drizzle
or prisma
. Instead, there are several examples
of strings being passed to the engine. Perhaps, I might work with that
approach or go deeper, but it would be nightmare in the long-term.
It's essential to have a common and secure API for
interacting with your DB. And just because libsql has more docs and examples
I went with the former option.
Anyway, rqlite
is worth taking a look at and trying on a side project.
PocketBase
PocketBase takes more of a backend-as-a-service approach than just being a database. Think of it as a lightweight alternative to platforms like Supabase, but powered by sqlite under the hood. It ships with a clean Admin UI for managing data, built-in authentication and file storage, and enough scaffolding to get small apps off the ground quickly. The database is just one part — the real value is the batteries-included backend.
dqlite
Distributed sqlite. Something similar to rqlite
. Really, starting with
the distribution algorithm and finishing with the idea. The software is great, but
would be very hard to use for modern web apps due to other goals.
dqlite
is tightly coupled to the C ecosystem, with bindings that
are still limited compared to the rich SDKs and ORMs SaaS teams expect.
You’ll spend more time wiring things together than shipping features.
To summarize, here's a table:
Solution | Approach | Best for | Gotchas / Limitations |
---|---|---|---|
libsql | Fork of sqlite | SaaS apps needing sqlite compatibility | WAL checkpoint bottlenecks; still inherits sqlite limits |
rqlite | Wrapper + Raft | Distributed apps needing consistency | Weak ORM ecosystem; examples mostly raw SQL strings |
dqlite | Wrapper + Raft | IoT / edge clusters, embedded HA systems | Tightly coupled to C; poor ecosystem for SaaS workloads |
PocketBase | Backend-as-a-service on sqlite | Small apps, quick prototypes, Supabase-like workflows | Limited scalability; more BaaS than standalone DB |
My personal experience
In our SaaS app, we’ve been running on libsql for almost a year now.
Overall, the product and support have been good.
The main challenge we hit wasn’t specific to libsql itself, but rather a
fundamental aspect of using sqlite in production: wal
mode bottlenecks.
SQLite’s checkpointing mechanism can occasionally create performance surprises. In our case, one long-running query triggered checkpoint starvation, which slowed down everything else. Even though the fix was straightforward — forcing checkpointing manually, it was a good reminder that monitoring and query control are essential when working with sqlite at scale.
One obvious fix would be to abort long-running queries at the database level.
Funny enough, drizzle
— one of the most popular modern ORMs —
doesn’t support this yet. HAHA.
So while the database gives you the tools to prevent bottlenecks,
the ORM layer can sometimes get in the way.
Key takeaway: with SQLite-based databases, watch query execution time closely, add timeouts where possible, and anticipate bottlenecks. The engine is powerful, but it demands discipline.