The default assumption when building anything with embeddings is that you need a vector database — a separate service, deployed and monitored, with its own client library and operational surface. For a large-scale production system that is often correct. For a great many applications it is significant infrastructure added to solve a problem that fits in a single file.
SQLite with a vector extension stores embeddings alongside your ordinary tables and searches them in-process. For a surprising range of workloads, that is the whole answer.
What changed in 2026
- Extensions matured and consolidated. Vector search extensions for SQLite stabilized enough for production use, with cleaner distribution across language bindings.
- Local and on-device retrieval grew. As more applications ran models on the user's machine, keeping the retrieval index local rather than calling a service became a natural fit.
- Realistic scale limits became documented. Community benchmarks clarified where brute-force similarity search stays fast and where approximate indexing becomes necessary.
- Edge deployment patterns emerged. Distributing a read-only SQLite file containing a prebuilt index to many locations turned out to be a clean way to serve retrieval at the edge.
When SQLite is enough
| Corpus size |
Approach |
Practical verdict |
| Under 10,000 vectors |
Brute force in SQLite |
Fast; no reason to look further |
| 10,000 to 100,000 |
Brute force, possibly with prefiltering |
Usually fine; measure your latency target |
| 100,000 to 1 million |
SQLite with approximate indexing or careful filtering |
Workable; evaluate against alternatives |
| Over 1 million |
Dedicated vector database |
SQLite is the wrong tool |
| Heavy concurrent writes at any size |
Dedicated service |
Write concurrency is SQLite's real constraint |
The numbers matter less than the shape: brute-force similarity over a moderate corpus is a linear scan over a few tens of megabytes, which modern hardware does very quickly. The instinct that this must be slow comes from thinking about it as a database query rather than as a numerical operation over a contiguous array.
The filtering advantage
The underrated benefit is that your vectors live in a relational database. Filtering a vector search by tenant, date range, document type, or permission set is an ordinary WHERE clause, applied in the same query, with a real query planner deciding how to execute it.
Dedicated vector databases handle metadata filtering too, with varying quality and varying degrees of awkwardness in how filters compose with approximate indexes. In SQLite it is just SQL. For retrieval systems where most queries are scoped — which in practice is most enterprise retrieval — that removes an entire category of complexity.
It also means one backup, one file, one transaction boundary covering both your documents and their embeddings. No synchronization problem between a primary database and a separate index, which is a real and persistent source of bugs in split architectures.
If your corpus outgrows it, vector database comparison and RAG vector store comparison cover the graduation path.
Common mistakes
- Reaching for a vector database at prototype stage. It is infrastructure you can add later, and moving embeddings between stores is not hard.
- Storing embeddings as JSON text. Use the extension's binary format; text encoding wastes space and parsing time.
- Ignoring write concurrency. SQLite serializes writers. A read-heavy workload is fine; a write-heavy multi-process one is not.
- Forgetting to normalize vectors. Distance metric behavior depends on it, and the resulting quality problems look like a retrieval bug.
- Skipping chunking quality. The store matters far less than what you put in it — see RAG chunking strategies.
FAQ
How fast is brute-force search really?
For tens of thousands of vectors it is typically single-digit milliseconds on ordinary hardware. Benchmark with your dimension count and corpus size rather than trusting a general figure.
Can I use this in a serverless function?
Yes, and it is a good fit for read-only workloads where the database file is bundled or fetched. Write-heavy serverless use is a poor match.
Does it work with any embedding model?
The store is agnostic; it holds float arrays. Dimension count matters for storage size and search cost, not for compatibility.
When exactly should I migrate?
When search latency exceeds your target at your actual corpus size, or when concurrent write volume becomes the bottleneck. Migrate on a measurement, not on a hunch.
Where to go next
For SQLite beyond vectors, read SQLite in production and Postgres vs SQLite. For the retrieval quality that matters more than the store, RAG chunking strategies.