SQLite in 2026
by Alexis Hope,
I wrote my first SQLite article in 2011 while debugging an Adobe AIR app. The problem was a quoting edge case; the solution was a one-liner. SQLite was a curiosity — a file-based database you used when you didn’t want to run a server.
Fifteen years later, SQLite is having a moment that few databases get to have. It’s not just embedded tooling anymore. It’s in the browser, at the edge, in production analytics pipelines, and increasingly, in vector search. The same engine, radically new contexts.
Why SQLite Became Interesting Again
SQLite never went away — it’s one of the most widely deployed pieces of software in existence, embedded in every iOS and Android device, every browser, most operating systems. But for a long time it was treated as a dev convenience, not a production choice.
A few things changed that:
- WASM made it possible to run SQLite in the browser without a server
- Litestream showed that streaming SQLite WAL to object storage was a credible replication strategy
- Cloudflare D1 put SQLite at the edge, globally distributed
- Turso built a commercial offering around SQLite with multi-region replication
- Fly.io LiteFS brought distributed SQLite to containerised deployments
- sqlite-vec added vector similarity search as a first-class extension
The through-line is that SQLite’s single-file, zero-dependency architecture turns out to be an advantage at the edges of distributed systems — places where you want compute close to data without the overhead of a client-server database.
SQLite in the Browser via WASM
The SQLite team ships an official WASM build. Combined with the Origin Private File System API (OPFS), you get a persistent, queryable database that lives entirely in the browser — no round trips, no server.
import { default as initSqlJs } from 'sql.js';
const SQL = await initSqlJs({
locateFile: file => `/wasm/${file}`,
});
const db = new SQL.Database();
db.run(`
CREATE TABLE events (id INTEGER PRIMARY KEY, name TEXT, ts INTEGER);
INSERT INTO events VALUES (1, 'page_view', ${Date.now()});
`);
const result = db.exec('SELECT * FROM events');
console.log(result[0].values); // [[1, 'page_view', 1710494400000]]
For persistence across sessions, wa-sqlite supports OPFS as a VFS backend, giving you a real durable store with no server involved. This is a genuine architectural option for offline-capable analytics dashboards or annotation tools where you want to process data locally before syncing.
Cloudflare D1
D1 is Cloudflare’s managed SQLite offering. Each database is a SQLite file that runs in a Worker, colocated with your compute. You query it with a lightweight client that speaks directly to the Workers runtime.
export default {
async fetch(request, env) {
const { results } = await env.DB.prepare(
'SELECT * FROM products WHERE category = ?'
)
.bind('analytics')
.all();
return Response.json(results);
}
};
D1 handles replication, point-in-time recovery, and global reads transparently. The constraint is the SQLite data model — no concurrent writes, no joins across databases. For read-heavy workloads at the edge (content APIs, feature flags, user config) it’s a very clean fit. For write-heavy transactional workloads, it’s not the right tool.
The combination of D1 + Cloudflare Workers + WASM gives you a stack where SQLite is present both server-side at the edge and client-side in the browser — with the same query language throughout.
Litestream: Replication Without Infrastructure
Litestream is a streaming replication tool for SQLite. It tails the Write-Ahead Log and continuously ships changes to S3-compatible object storage. Recovery is a restore from the stream.
# litestream.yml
dbs:
- path: /data/app.db
replicas:
- url: s3://my-bucket/app.db
Run it as a sidecar:
litestream replicate -config /etc/litestream.yml
This fundamentally changes the operational story for SQLite. You get continuous backup with low RPO, point-in-time recovery, and multi-environment replication — all without running a database server. For applications where write concurrency is low and you want operational simplicity, Litestream is a compelling argument for SQLite in production.
sqlite-vec: Vector Search as an Extension
sqlite-vec is a SQLite extension that adds vector similarity search using virtual tables. It’s written in C with no dependencies, loads as a standard SQLite extension, and works anywhere SQLite does — including WASM.
This matters for NLP and information retrieval work. You can store document embeddings alongside your structured data in the same file, query them with cosine or L2 distance, and join the results back to your content table — all in SQL.
Schema
CREATE VIRTUAL TABLE embeddings USING vec0(
document_id INTEGER,
embedding FLOAT[384]
);
FLOAT[384] declares the vector dimension — this matches common sentence embedding models like all-MiniLM-L6-v2.
Inserting vectors
INSERT INTO embeddings (document_id, embedding)
VALUES (1, '[0.12, 0.84, ...]');
In practice you’ll be serialising float arrays from your embedding model. With Python:
import sqlite3
import sqlite_vec
import struct
import numpy as np
con = sqlite3.connect("search.db")
con.enable_load_extension(True)
sqlite_vec.load(con)
def serialize(vector: list[float]) -> bytes:
return struct.pack(f"{len(vector)}f", *vector)
embedding = model.encode("natural language processing")
con.execute(
"INSERT INTO embeddings VALUES (?, ?)",
[doc_id, serialize(embedding)]
)
Querying by similarity
SELECT
d.title,
d.body,
e.distance
FROM embeddings e
JOIN documents d ON d.id = e.document_id
WHERE e.embedding MATCH ?
AND k = 10
ORDER BY e.distance;
The MATCH + k syntax runs a KNN search, returning the 10 nearest vectors by distance. Joining back to the documents table gives you the content in a single query.
Why this is interesting
The obvious comparison is pgvector in Postgres or a dedicated vector database like Qdrant. Those are the right choices when you need distributed writes, tenancy, or very large corpora. But sqlite-vec covers a real gap: local vector search with zero infrastructure, in the same file as your structured data. For a pipeline that processes documents, extracts embeddings, and needs to serve similarity queries from a single binary — this is a very clean architecture.
For nlpcitations.com in particular, the ability to store citation embeddings alongside structured metadata and query them with standard SQL joins is the kind of simplicity that’s hard to get from a dedicated vector store.
Turso: Multi-Region SQLite
Turso is a managed database built on libSQL, a fork of SQLite that adds networking and replication. You get a primary write database and replicas in locations close to your users, with sub-millisecond local reads.
import { createClient } from '@libsql/client';
const db = createClient({
url: 'libsql://my-db.turso.io',
authToken: process.env.TURSO_TOKEN,
});
const result = await db.execute('SELECT * FROM articles LIMIT 10');
The key distinction from D1 is that Turso exposes a proper client library, supports embedded replicas (a local SQLite file that syncs from the remote), and works outside the Cloudflare ecosystem. If you’re running on Fly.io, Railway, or your own VPS, Turso is the more portable option.
When Not to Use SQLite
SQLite is a single-writer database. Concurrent write throughput is limited by a single lock on the file. If your workload has multiple processes writing simultaneously — a web server with real concurrency, a pipeline with parallel workers — you will hit contention. For that use case, Postgres is still the right answer.
Similarly, SQLite is not a substitute for ClickHouse on analytical workloads at scale. For columnar scans over billions of rows, partitioned aggregation, and compression-aware query planning, you need a purpose-built OLAP engine. SQLite handles analytical queries well at modest scale — think thousands to low millions of rows — but it degrades past that.
The cases where SQLite wins are the ones where its constraints are not constraints: single-process applications, edge deployments, browser-local storage, CLI tools, embedded search, and situations where operational simplicity is a genuine priority.
The Broader Pattern
What makes SQLite’s resurgence instructive is that it wasn’t driven by new features in the database itself. The engine has been stable for years. What changed was the infrastructure around it — WASM runtimes, edge compute, object storage cheap enough to treat as a WAL target, and a community that built replication and vector search as extensions rather than requiring a rewrite.
That’s a useful lens for evaluating any mature technology. The question isn’t just what it does — it’s what becomes possible when the surrounding ecosystem changes.