SQLite Was Never Built for This. I'm Using It Anyway.
Every App, A New Database
PostgreSQL has been my default database since I started backend development, after a brief time with MongoDB. It solved most of my problems, but one issue kept coming up: operational overhead. Every time I needed to create an app, no matter how small, I spun up a Postgres database. This felt reasonable since it is what I planned to use in production anyway. But as more projects came in, the overhead compounded. Provisioning, migrations, connection pooling, role assignment. Not every app needs all of this, and in most cases my apps would work the same way on any SQL-compatible database.
So I started asking a more honest question: not "is Postgres the right database," but "do I actually need a database server at all for every app I build?" I looked at the alternatives. NoSQL databases solve a different problem and come with higher vendor lock-in risk. Managed options like PlanetScale or CockroachDB introduce their own lock-in. Cloudflare D1 is SQLite under the hood but ties you to Cloudflare's infrastructure. Most alternatives either carried the same operational weight I was trying to escape, or traded it for lock-in.
Only one option was SQL-compatible, lightweight, had no vendor lock-in, and was mature enough to take seriously. SQLite. Which was surprising, because SQLite was never built for this.
Why SQLite Was Dismissed
Choosing SQLite sounds weird if you think about it. It was never meant to be a general purpose database. SQLite was created for embedded systems and local application storage, with no server, no networking, no concurrent writes, and no replication. Which embedded system needs any of that? None.
Those limitations were intentional, not oversights. In an embedded system, writes are almost always sequential. Each system owns its own data, so replication makes no sense. And exposing a local database to the internet would be pointless. Adding those features would make SQLite bloated for the environment it was designed for.
The problem is that the reputation stuck. As internet applications grew more complex, the criticism of SQLite never updated. Developers kept dismissing it for server use based on limitations that made perfect sense in 1999 but were increasingly being addressed by the ecosystem around it.
The Ecosystem Today
In 2022, a team of developers forked SQLite to create libSQL. The goal was to add features SQLite never had without touching the original codebase. SQLite stays light and embedded, while libSQL serves a different purpose. The core additions libSQL brought were networking and replication, meaning web applications and server-side apps could now rely on it for data persistence, not just embedded devices. It can also be distributed, which is a direct benefit for read-heavy workloads.
SQLite needs no server to run locally, but a production database needs something to manage persistence, backups, and external connections. sqld is the libSQL server. It is what you actually run when self-hosting. It handles incoming connections, manages the database file, and exposes libSQL over HTTP, making it accessible to external applications and services without the operational weight of a full Postgres server.
The same team later rewrote SQLite from scratch in Rust and named it Turso. A ground-up rewrite with the same SQLite interface, but built with memory safety, async I/O, and production server use in mind. Turso also ships as a managed cloud product called Turso Cloud. The rewrite made features possible that are difficult to implement on top of C code, including native vector search, CDC, and MVCC.
What Changed
Network access was the first real unlock. SQLite was never accessible over the internet because it was never designed to be. libSQL changed that by adding an HTTP-native protocol. Most of the internet communicates over HTTP and HTTPS natively. Platforms like Cloudflare Workers do not allow raw TCP connections at all, which is why Postgres cannot run there without a dedicated HTTP wrapper. libSQL works on these platforms out of the box.
Replication changed too, and this one surprised me more. In a traditional setup, a read replica is a separate server you provision, configure, and pay for independently. With libSQL, a replica is just a local file that lives on the same machine as your application. Every app instance becomes its own replica automatically. Scale your app, you scale your replicas. No extra infrastructure, no extra cost.
Memory usage is also worth paying attention to, especially if you run multiple services. A Postgres server uses roughly 50-150MB at baseline, and that number grows with every connection and query. A libSQL instance embedded in your application uses 1-2MB. For someone spinning up multiple apps, that difference adds up fast.
What’s Still Experimental
Not everything is solved yet. MVCC allows multiple writers to write to a database simultaneously without blocking each other. Turso has implemented it, but it is still experimental right now. The documentation is thin and I would not use it for critical production data yet.
Without MVCC, SQLite processes writes sequentially. One write must complete before the next one starts. For most apps this is fine. But in write-heavy workloads the math gets uncomfortable. If each write takes 1ms, the 100th writer waits 100ms. At 3000 concurrent writers, that queue becomes a real problem. The replica-per-instance model helps in distributed apps since each instance writes to its own local file, but within a single instance the limitation still applies.
The tooling is also not there yet. I noticed this while going through the docs. Postgres has decades of mature, well-documented tooling behind it. Turso is catching up but it is not at that level. Complex query performance also still favors Postgres. If your workload is heavy on analytical queries or complex joins, Postgres is genuinely the better choice here.
Based on the pace of development, I think Turso might become the default for small and medium scale apps, reducing the overhead of managing a database server entirely. That is a prediction, not a conclusion.
In the next post, I will set up a real app with Turso and walk through how everything works together. How to set up a Turso database and connect it to a TypeScript app.
메타데이터
- post_id
- a4663efc85af
- slug
- sqlite-was-never-built-for-this-im-using-it-anyway-a4663efc85af
- url
- https://medium.com/@dhamivibez/sqlite-was-never-built-for-this-im-using-it-anyway-a4663efc85af
- canonical_url
- https://medium.com/@dhamivibez/sqlite-was-never-built-for-this-im-using-it-anyway-a4663efc85af
- author_url
- https://medium.com/@dhamivibez
- status
- ok
- fetched_at
- 2026-06-09 15:37:30