There are over one trillion SQLite databases in active use right now. Not million. Not billion. Trillion. It's in every iPhone, every Android phone, every Mac, every Windows 10+ machine, every Firefox and Chrome browser, every Airbus A350, and both Mars rovers. It's likely used more than all other database engines combined. And yet, when someone asks "what database should I use?" on Reddit or Hacker News, the top answer is always the same: "just use Postgres."
I've been guilty of this too. For years, I reached for PostgreSQL reflexively — connection pooling, managed instances, Supabase, the whole stack. Then I built a project with SQLite and Litestream, and the simplicity was so aggressive it felt like cheating.
The Numbers That Should Change Your Mind
SQLite isn't just popular. It's the most deployed software component of any type, period. Since every smartphone ships with SQLite, and there are over 4 billion smartphones in active use — each containing hundreds of SQLite databases — the total deployment count is staggering.
As of 2026, 2,718 verified companies use SQLite in production, including Amazon, Apple, Microsoft, NVIDIA, and Walmart. Discord, Airbnb, Dropbox, and Netflix all rely on it for production workloads. Expensify processes billions of dollars in financial transactions through SQLite.
And something shifted in 2025-2026. A constellation of new tools — Turso, Cloudflare D1, Litestream, and libSQL — converged to solve SQLite's real limitations while preserving its core simplicity. The community started calling it the "SQLite Renaissance."
This isn't a toy database getting hyped by indie hackers. This is the most battle-tested storage engine on Earth getting a modern infrastructure layer. And most developers are still ignoring it.
Why Everyone Says "Just Use Postgres" (And Why They're Partly Wrong)
The "just use Postgres" advice isn't bad. PostgreSQL is excellent. I use it for this blog (Neon, specifically). For most production web applications with concurrent writes, multiple users, and complex queries, Postgres is the correct choice.
But here's what the Postgres orthodoxy gets wrong: it treats every project like it needs a client-server database. It assumes you need connection pooling, replication, managed hosting, and the operational overhead that comes with running a database server. For a lot of projects, you don't.
SQLite is not a client-server database. It's a library that links directly into your application. All data lives in a single file on disk. No setup, no server process, no configuration, no connection strings, no port management, no pg_hba.conf, no pgBouncer. You open a file. You run queries. You close the file.
The performance implications are profound. For a simple SELECT by primary key, Cloudflare D1 from a Worker achieves roughly 0.5ms latency. For read-heavy workloads, local SQLite is 100-1,000x faster than any network database. There's no TCP connection, no serialization, no round-trip. Your data is just... there.
Here's the question nobody asks: do you actually need a database server?
If your app is a personal project, a blog, an internal tool, a CLI, a mobile app, a desktop app, a single-server web app with moderate traffic, or an edge function — the answer is probably no. And for every one of those cases, SQLite is not just adequate. It's better.
What Changed: The SQLite Renaissance
The old criticism of SQLite was valid: no replication, no backup story, one writer at a time, no network access. In 2024-2026, every one of those problems got solved.
Litestream: The Backup Problem Is Gone
Litestream runs as a background process that continuously replicates your SQLite database to S3, Azure Blob, Google Cloud Storage, or any S3-compatible store. It uses SQLite's Write-Ahead Log (WAL) to stream changes incrementally — no full database dumps, no scheduled backups, no data loss window.
# Install Litestream
sudo apt install litestream
# Configure replication to S3
cat > /etc/litestream.yml << 'EOF'
dbs:
- path: /data/app.db
replicas:
- url: s3://my-bucket/app.db
EOF
# Start replicating
litestream replicate
That's it. Your SQLite database is now continuously backed up with point-in-time recovery. If your server dies, restore from S3 and you've lost at most a few seconds of data. Litestream delivers 10x faster replication than periodic dumps, and the new LTX format with compaction makes it even more efficient.
The "but what about backups?" objection to SQLite in production is dead. Litestream killed it.
Turso and libSQL: SQLite Goes Distributed
Turso is the most ambitious bet in the SQLite ecosystem. Built on libSQL — an open-source fork of SQLite — it adds everything SQLite was missing:
- Embedded replicas that sync from a primary server, giving you local read performance with replicated durability
- BEGIN CONCURRENT for multi-writer support — the biggest gap in vanilla SQLite
- Server mode via HTTP and WebSockets — now your SQLite can serve network requests
- Native vector search — no separate vector database needed for AI use cases
- Edge deployment — databases replicated to locations closest to your users
import { createClient } from "@libsql/client";
const db = createClient({
url: "libsql://my-database-my-org.turso.io",
authToken: "...",
});
const result = await db.execute("SELECT * FROM users WHERE id = ?", [userId]);
The libSQL fork preserves full SQLite compatibility while treating SQLite's limitations as engineering problems to solve. And because it's a fork, not a wrapper, the performance characteristics remain fundamentally SQLite — no ORM overhead, no connection pooling, no serialization layer.
Cloudflare D1: SQLite at the Edge
Cloudflare D1 is a managed, serverless SQLite database that runs at the edge. It reached general availability in April 2024 and has been maturing rapidly:
- Automatic read replication — reads served from the nearest edge PoP globally
- Time Travel — 30-day point-in-time recovery
- Scale-to-zero billing — pay only for queries and storage, no idle charges
- Zero egress fees — Cloudflare's signature cost advantage
Pricing is minimal: roughly $0.001 per million rows read, $1.00 per million rows written, $0.75/GB/month storage. For a typical read-heavy application, the monthly bill is often under $5.
The limitation: D1 databases cap at 10 GB and sustain only 500-2,000 writes per second. That's fine for most applications — but if you need heavy write throughput, this isn't your tool.
The Comparison Table You Actually Need
Most articles compare SQLite to Postgres on the wrong dimensions. They benchmark raw query speed on large datasets where Postgres obviously wins. Here's the comparison that matters for architecture decisions:
| Dimension | SQLite | PostgreSQL |
|---|
| Setup time | 0 (it's a library) | 30 min - 2 hours |
| Connection management | None needed | pgBouncer, connection pooling |
| Hosting cost | $0 (file on disk) | $7-50/month minimum |
| Read latency (local) | Under 1 ms | 2-10 ms (network hop) |
| Write concurrency | 1 writer (WAL mode) | Hundreds concurrent |
| Max database size | 281 TB (theoretical) | Unlimited |
| Backup complexity | Litestream (5 min setup) | pg_dump, WAL-G, managed backup |
| Replication | Litestream, Turso, D1 | Built-in streaming replication |
| Edge deployment | Native (Turso, D1) | Requires managed service |
| Serverless fit | Perfect | Connection pooling nightmares |
| Multi-tenant patterns | One DB per tenant (natural) | Schema per tenant (complex) |
| Operational overhead | Near zero | Ongoing (vacuuming, monitoring, etc.) |
| Extensions/ecosystem | Limited | Massive (PostGIS, pgvector, etc.) |
The pattern is clear: SQLite wins on simplicity, cost, and read latency. Postgres wins on write concurrency, ecosystem, and scale. Everything else is noise.
WAL Mode: The Setting That Makes SQLite Production-Viable
If you're running SQLite and haven't enabled WAL mode, you're leaving performance on the table. In the default rollback journal mode, writers block all readers. WAL mode fixes this completely.
PRAGMA journal_mode=WAL;
PRAGMA busy_timeout=5000;
PRAGMA synchronous=NORMAL;
PRAGMA cache_size=-64000; -- 64MB cache
PRAGMA foreign_keys=ON;
With WAL enabled:
This is the single most important configuration for production SQLite. Without WAL mode, you shouldn't run SQLite for anything with concurrent access. With it, a surprising number of workloads become feasible.
The Multi-Tenant Trick: One Database Per Customer
Here's a pattern that SQLite does better than any other database: one database file per tenant.
In Postgres, multi-tenancy is painful. You either put all tenants in one database with a tenant_id column (leaky abstractions, cross-tenant query risks), or use one schema per tenant (migration nightmares, connection pooling complexity), or run separate Postgres instances (expensive, hard to manage).
With SQLite, each tenant gets their own file:
/data/tenants/
tenant_001.db
tenant_002.db
tenant_003.db
...
Each tenant's data is completely isolated. Backups are per-tenant. Migrations run per-file. You can delete a tenant by deleting a file. You can move a tenant to a different server by copying a file. There's no cross-contamination, no row-level security policies, no shared connection pools.
Turso takes this pattern to the edge — each tenant's database can be replicated to the location closest to them. Turso scales to millions of database instances, making this pattern viable at scales that would be absurd with Postgres.
This is genuinely one of the best architectural patterns I've used. If your SaaS has tenant isolation requirements — compliance, data residency, per-tenant backup/restore — the SQLite-per-tenant pattern is elegant in a way that Postgres multi-tenancy never will be.
The Serverless Connection Problem That Nobody Talks About
Here's something that drives me crazy: watch any serverless tutorial on YouTube. Step 1: write a function. Step 2: connect to Postgres. Step 3: realize your cold starts are 2-3 seconds because establishing a database connection takes 500ms and your connection pool expired.
Serverless functions and traditional databases are fundamentally at odds. A Lambda function spins up, opens a connection to Postgres, runs a query, and shuts down. The next invocation does it all again. At scale, you get hundreds of ephemeral connections hammering your database's connection limit. That's why PgBouncer exists. That's why Neon built connection pooling into their product. That's why Supabase runs pgBouncer as a sidecar.
SQLite doesn't have this problem because there's no connection to establish. You open a file. You read bytes from disk. In a Cloudflare Worker, D1 is just... there. No connection string, no pool management, no cold start penalty for the database layer. The function boots in 5ms and the first query runs in under 1ms.
This is why Cloudflare built D1 as their database product for Workers. Not Postgres, not MySQL. SQLite. Because the serverless execution model and the embedded database model are a natural fit. One is ephemeral compute, the other is ephemeral connections. Together, they just work.
If you're building on serverless — Cloudflare Workers, Vercel Edge Functions, Deno Deploy — SQLite (via D1 or Turso) eliminates an entire category of infrastructure pain. And that's worth more than any benchmark comparison.
When NOT to Use SQLite
I'm not going to pretend SQLite is right for everything. Here's where you should absolutely use Postgres (or MySQL, or something else):
Heavy concurrent writes. SQLite supports one writer at a time in WAL mode. If your workload involves hundreds of simultaneous write transactions — a social media app, a real-time collaboration tool, a trading platform — SQLite will bottleneck. libSQL's BEGIN CONCURRENT helps, but Postgres is still better for genuinely write-heavy workloads.
Complex analytical queries on large datasets. If you're running JOINs across tables with hundreds of millions of rows, Postgres with proper indexing and a query planner will outperform SQLite. SQLite's query planner is good for a single-file database, but it's not in the same league as Postgres on complex plans.
You need PostGIS, pgvector, or other extensions. The Postgres extension ecosystem is unmatched. If your application needs geospatial queries, full-text search with ranking, or advanced JSON operations, Postgres is the clear winner. SQLite has FTS5 and JSON functions, but the depth of Postgres extensions is far greater.
Your team already knows Postgres. If your entire team has years of Postgres experience and your infrastructure is built around it, switching to SQLite for the sake of it is a bad idea. The best database is the one your team can operate confidently.
Multiple application servers writing to the same database. If you have 5 application servers behind a load balancer, they can't all write to the same SQLite file over a network share. This is where Turso or D1 step in — but vanilla SQLite on a shared filesystem is a non-starter.
You need advanced access control. SQLite has no concept of users, roles, or permissions. It's a file — anyone who can read the file can read all the data. Postgres offers row-level security, role-based access control, and fine-grained permissions. If your database serves multiple applications with different access levels, you need a real server.
Datasets over 10-50 GB. While SQLite theoretically supports databases up to 281 TB, performance degrades on datasets larger than a few tens of gigabytes. If you're dealing with data at that scale, you're also likely dealing with the kind of query complexity and concurrency that Postgres handles better.
The Practical Path: How to Start With SQLite
For a new side project or SaaS MVP:
# Use SQLite directly with your framework
# Django: sqlite3 is the default (you've been using it all along)
# Rails: `rails new myapp --database=sqlite3`
# Node.js: better-sqlite3 is the gold standard
npm install better-sqlite3
const Database = require('better-sqlite3');
const db = new Database('app.db');
// WAL mode + performance settings
db.pragma('journal_mode = WAL');
db.pragma('busy_timeout = 5000');
db.pragma('synchronous = NORMAL');
db.pragma('cache_size = -64000');
// Your queries are now sub-millisecond
const user = db.prepare('SELECT * FROM users WHERE id = ?').get(userId);
Add Litestream for backup:
# Replicate to S3 every 10 seconds
litestream replicate /data/app.db s3://my-bucket/app.db
For a production app that needs edge performance:
Use Turso. Their SDK is a drop-in replacement for standard SQLite clients:
# Install the Turso CLI
curl -sSfL https://get.tur.so/install.sh | bash
# Create a database
turso db create my-app
# Create a replica in Frankfurt
turso db replicate my-app fra
For serverless on Cloudflare:
D1 is a native SQLite experience inside Workers:
// In a Cloudflare Worker
export default {
async fetch(request, env) {
const { results } = await env.DB.prepare(
"SELECT * FROM products WHERE category = ?"
).bind("electronics").all();
return Response.json(results);
},
};
What I Actually Think
The "just use Postgres" advice is lazy. Not wrong — lazy. It's the database equivalent of "just use React" or "just use AWS." It's the safe answer that's right 60% of the time but ignores the 40% of cases where a simpler solution would be dramatically better.
I think SQLite is the most underused database in web development. Not because it can replace Postgres everywhere — it can't. But because developers default to running a database server for applications that don't need one. They spin up a $15/month managed Postgres instance, wrestle with connection pooling in their serverless functions, deal with cold start latency for database connections, and manage backup schedules — all for an app that could have used a single file on disk.
I think the Turso/libSQL bet is the most interesting thing happening in databases right now. The idea of making SQLite distributed — keeping the simplicity of a single-file database while adding replication, edge deployment, and concurrent writes — is architecturally beautiful. If they pull it off (and they're making real progress), it changes the calculus for a huge number of applications.
I think Litestream should be the default for any single-server application using SQLite. It's so simple to set up that there's no excuse not to have continuous backups. The "SQLite isn't safe for production because you might lose data" argument was valid five years ago. It's not anymore.
I think the SQLite-per-tenant pattern is genuinely better than Postgres multi-tenancy for most SaaS applications under 10,000 tenants. The operational simplicity — backup one tenant, delete one tenant, migrate one tenant — is worth more than the theoretical scalability advantages of a shared Postgres instance.
And I think the best database is almost never the one with the most features. It's the one with the least operational overhead for your specific use case. For a surprisingly large number of applications, that's a single file called app.db, backed up to S3 every ten seconds, serving queries in under a millisecond.
I think the biggest mental block developers have with SQLite is that they equate "embedded" with "amateur." That association is wrong. SQLite has been in continuous development since 2000. It has more test code than application code — over 100% branch test coverage with billions of test cases. It's one of the most thoroughly tested codebases in existence. The D. Richard Hipp model of "one maintainer, extreme testing, no corporate sponsor" has produced software that's been more reliable than most enterprise databases.
The irony is thick. Developers will spin up a managed Postgres instance with a 99.95% uptime SLA and worry about durability. Then they'll dismiss the database that literally runs on Mars rovers because "it's just a file."
Stop defaulting to Postgres. Think about what you actually need. The answer might be the database that's already on every device you own.
Sources
- SQLite — Most Widely Deployed Database Engine
- SQLite — Appropriate Uses
- SQLite — Well-Known Users
- SQLite — Write-Ahead Logging
- Landbase — Companies Using SQLite in 2026
- DEV Community — The SQLite Renaissance
- SitePoint — Post-PostgreSQL: Is SQLite on the Edge Production Ready?
- Turso — Official Website
- Turso — libSQL Documentation
- Turso — Why SQLite Is Great for the Edge
- WebProNews — Turso Enables Concurrent Writes in libSQL
- Litestream — Official Website
- Litestream — GitHub Repository
- Cloudflare — D1 Documentation
- Cloudflare — D1 Pricing
- Fly.io — SQLite Internals: WAL
- DEV Community — Everyone Is Wrong About SQLite
- LogSnag — The Tiny Stack