Guide
Local Vector Database (Local Vector DB): Which One to Pick (2026)

finn
Updated November 4, 202643 min read
A local vector database lets your app, or an AI agent you're building, search your own documents by meaning, on your own computer, with no server to run and no online service to pay. Ask "how do I get my money back?" and it finds your refund policy, though the two share no words.
It keeps each passage, a few sentences of your documents, as a vector: a list of numbers that stands for its meaning. Pick sqlite-vec if you hesitate. It is a free add-on for SQLite, the small database that lives in one file. Tested on 100,000 Wikipedia paragraphs on 4 November 2026, it returned the ten nearest passages to every question. It used the least memory of the main options, and two programs could share its file.
Take LanceDB, another free database that runs inside your program, if your documents will grow well past 100,000 passages. If your app runs online rather than on your computer, you need a database on a server. With only a few documents, you may need no vector database at all.
By the numbers
51%
The most LanceDB's default index found of the nearest passages in 100,000 Wikipedia paragraphs, built four times. The least was 49%.
Measured with LanceDB 0.41.0, 4 Nov 2026
37 ms
Typical search time of sqlite-vec over 100,000 paragraphs with no index, without missing a nearest passage.
Measured with sqlite-vec 0.1.9, 4 Nov 2026
2.9 GB
Memory used by Qdrant's local mode, the light version of a server database, to search 100,000 paragraphs. It warns above 20,000.
Measured with qdrant-client 1.20.0, 4 Nov 2026
188 KB
Installed size of sqlite-vec alone. With fastembed, which runs the embedding model, 148 MB, against 351 MB for Chroma.
Installed on macOS, 4 Nov 2026
Which local vector DB to pick, case by case
Start from sqlite-vec, and move away from it only for a reason listed here. Your coding agent, the AI that writes your code (Claude Code, Cursor, Lovable and the like), does the setting up, and this page gives you what to ask it. The figures come from a test run on 4 November 2026 on 100,000 Wikipedia paragraphs. The picks are this page's own judgment.
The test measures the nearest passages: the ones the embedding model, the AI that turns text into vectors, rates closest in meaning to the question. Nearest passages don't always answer the question. That depends on the model and on how your text is cut, which matter more than the database.
| Database (version tested) | What it is | Two programs, and languages | Best for |
|---|---|---|---|
| sqlite‑vec 0.1.9 | An add-on for SQLite: your vectors sit in a table of an ordinary .db file | Two programs, one writing at a time. Languages: Python, JavaScript, Go, Rust, Ruby, browsers | One file that several programs share, next to your other data |
| LanceDB 0.41 | A database that runs inside your program and stores each table as a folder | Two programs, with one setting. Languages: Python, JavaScript, Rust | A collection that will grow, and can later move to online storage |
| Chroma 1.5.9 | A vector database that can run inside a Python program, with no server | One program: its makers advise against two. Language: Python only, since JavaScript needs a Chroma server | A first try in one Python program, because it brings its own embedding model |
| Qdrant local mode 1.20 | A Python-only imitation of Qdrant, a vector database normally run as a server | One program: the folder is locked. Language: Python only | Trying out an app that will later move to a Qdrant server, under 20,000 passages |
Here is the same choice, case by case.
- You only want to ask questions of your own documents: you may not need to build anything. AnythingLLM, a desktop app for chatting with your files, has LanceDB built in. Its documentation says: "Your vectors never leave AnythingLLM when using the default option." The AI model you connect to it is a separate choice, and that model reads your passages.
- One program on your computer: sqlite-vec, LanceDB, Chroma or Qdrant's local mode all work. Chroma asks the least of your coding agent, because it brings its own embedding model.
- An app on your computer stays open while a small program adds documents: sqlite-vec. LanceDB works too, if your coding agent sets its
read_consistency_intervalto zero. Each search then looks for new passages. - A Python program fills the database and a JavaScript app reads it: sqlite-vec or LanceDB. Both gave identical results when Node.js, the program that runs JavaScript on a computer, opened what Python wrote.
- Searches stay inside one document, or one person's notes, in an app you trust: sqlite-vec. Ask your coding agent to make the document a partition key, which stores each document's vectors together. A search limited to 1% of the paragraphs took 0.4 ms that way, against 20 ms without it.
- Customers log in and must not see each other's data: a database on a server. A file has no logins, so any program that can read it reads all of it.
- Your collection will pass 100,000 passages: LanceDB. It compares your question with every passage until you build an index, so you can start without one. Zvec, a database from Alibaba, and Chroma have indexes that did better at their default settings, but neither suits two writing programs. Dosu, an assistant that answers questions about code projects, moved to LanceDB from pgvector and reported in 2025 "millisecond search across millions of vectors".
- Your app runs online: pgvector, on a server. A file on your computer can't follow an app hosted online. Supabase, the software Lovable's backend is built on, lists pgvector as an extension, so ask your coding agent whether your app's database can switch it on.
- Two computers write to it, or your collection heads past ten million passages: a server too. A local file serves programs on one machine, and the makers' own limits start around that size.
What a vector database is, and what it lets you do
A vector database finds passages by what they mean, where an ordinary search finds the words you typed. Suppose your help page says "refund policy" and a customer types "how do I get my money back?". A search for those words finds nothing, because no word matches. A vector database finds the page, because the two mean nearly the same thing.
It does this with an embedding model, a small AI model that turns a passage into a list of numbers. Passages with close meanings get close numbers. That list is the vector, also called an embedding. The database keeps those lists and finds the ones nearest your question.
That lets you build three things:
- An assistant that answers from your documents. Before the AI model that writes the answer starts, your program fetches the matching passages and hands them to it. This is called RAG, for retrieval-augmented generation.
- A search across your own notes, files or PDFs. You type what you remember in your own words, and the search doesn't need the file's exact wording.
- A memory for an AI agent you're building. OpenClaw writes what it learns to plain text files, then finds it again through sqlite-vec and a keyword search. A note turns up "even when the wording differs from the original text", its documentation says. The AI agent you're building can also search your database as one of its tools, and connecting an AI agent to your apps covers how.
RAG is less complicated to set up than it sounds. I've put it in products of my own. In a large database, searching by meaning gives a wider view and better results than telling the search to look for one exact word.
"Local" means the database runs inside your own program. Its data sits in a file or a folder on your disk, and nothing goes over a network. Developers call such a piece of code a library, because your program loads it.
A self-hosted database is different: a separate server program you run yourself, on your computer or on a rented one. Docker, a tool that runs server programs in a sealed box, is the usual way. An online service, such as Pinecone, runs the database for you and charges for it.
All the local databases on this page are free and open source (GitHub, 4 November 2026). What they cost you is disk space and memory.
A local database alone doesn't keep your text private. The embedding model sees every passage you store and every question you ask. The one used in this page's test, all-MiniLM-L6-v2, runs on your computer. An online one, such as OpenAI's, receives that text on OpenAI's servers.
The AI model that writes the answer is separate again. To keep that one on your computer too, read what self-hosted AI agents take.
Do you need a vector database at all?
Not always, and that is this year's debate. A few documents, or searches for exact names, need no vector database. The makers of AI coding agents disagree on the rest. Their test case is code, a text full of exact names, so their results carry over to your documents only in part.
Claude Code, Anthropic's coding agent, works without one. Boris Cherny, its lead engineer, told the Latent Space podcast in 2025 that very early versions used RAG over an index of the code. The team then moved to agentic search: the agent runs plain text searches, as many as it needs, and reads what it finds.
In his words, this "outperformed everything", judged on some internal tests but "mostly vibes". He adds that an index falls out of date as the code changes, and that it is one more copy of your code to protect, wherever it is stored. The price, he says, is "latency and tokens": longer waits, and more of the tokens AI models bill by.
Cursor, a code editor built around an AI agent, found the opposite for large projects. It reported in November 2025 that adding search by meaning to an agent that already used text search gave 12.5% more accurate answers on average. That figure comes from Cursor's own test, with an embedding model it trained itself. Its conclusion is that the two together work best.
The headline of the debate came on 30 September 2026. turbopuffer, a company whose first product was a vector database, titled a post "rip vector database". Its customers include Cursor and Notion. The post describes a change inside its product: its vector index becomes "just another" index, next to text search. So vector search stays, as one tool among others.
Three benchmarks, shared tests of search, show why nobody agrees. Two test different kinds of text, and the third tests size. All three use BM25, the classic keyword ranking, which scores each document by the words it shares with the question. That goes further than looking for one exact word.
- On a company's internal documents, keyword search won. Onyx, which sells company search, published a test called EnterpriseRAG-Bench in May 2026. It asks 500 questions of 500,000 made-up Slack messages, emails and tickets. Given BM25's results, an AI model answered 68.8% correctly. Given vector search's results, it answered 51.4%. The authors suggest embedding models rarely met project code names and internal acronyms in training.
- On web pages, vector search won. A test called BrowseComp-Plus, published in August 2025, asks 830 hard questions of about 100,000 web documents. With OpenAI's GPT-5 doing the searching, vector search led to 70.1% correct answers and BM25 to 55.9%.
- As a collection grows, keyword search holds up best. A study published in July 2026 ran Onyx's test on collections from 1,144 to 511,959 documents. On the smallest, an agent reading raw files answered 77.4% correctly, BM25 74.7% and vector search 58.1%. On the largest, BM25 answered 50.5%, the agent 30.7% and vector search 29.9%.
That last study also ran a separate check on 150 of the questions. An agent given BM25 as a tool did best: at the largest size it reached 69.4%, against 54.8% for BM25 alone on those questions.
So judge your own case by how much text there is and how people search it.
- A few dozen documents an agent can read each time: no database. There is nothing to build and nothing to keep up to date.
- Exact names, codes and references: keyword search. FTS5, SQLite's built-in keyword search, sits in the same file as sqlite-vec.
- People ask in their own words, across more text than an agent can read for each question: a vector database. Add keyword search beside it, as OpenClaw does.
How a vector database finds the nearest passages
Whichever database you pick, the work takes three steps.
First, your embedding model turns each passage of your documents into numbers. Developers call such a passage a chunk. The model used in this page's test, all-MiniLM-L6-v2, is small and open, and it returns 384 numbers per passage.
Second, the database keeps those lists next to the text and any details you add, such as a title or a date.
Third, your question goes through the same model, and the database returns the passages nearest your question. Nearness is measured as cosine distance: 0 means the model sees the same meaning, and larger means less alike.
The database can find those passages in two ways:
- Exact search compares your question with every passage. It never misses a nearest passage, and it takes longer as your collection grows. Developers also call it brute force.
- An index is a shortcut that skips most comparisons. Like a book's index, it gets you there fast. Unlike a book's index, it can miss some nearest passages.
Your coding agent will use these index names, so here is what each one does:
- HNSW builds a map that links each passage to its near neighbours, then walks the map towards your question. A setting usually called
efsays how many candidates it keeps during the walk. More means fewer misses and slower searches. - IVF groups passages into clusters and searches only the clusters nearest your question. A setting called
nprobessays how many clusters it searches. - PQ compresses each list of numbers into a few bytes. Distances become approximate, so some results are lost.
- SQ stores each number in one byte instead of four, which is four times smaller and slightly less exact.
LanceDB's IVF_HNSW_SQ index combines clusters, a map inside each cluster and one-byte numbers.
The test behind these figures
To choose on evidence, the test asks three things of each database: does it return the nearest passages, how long does it take, and how much memory and disk does it use. It ran on 4 November 2026 with each project's latest release, and it repeats a first run of 27 October.
The data was the first 100,000 paragraphs of 200 to 1,500 characters from Simple English Wikipedia, in its copy of 1 November 2023. That is the length of about 80 books. At 432 characters on average, they make 43 million characters, or about 7 million words, and a long book holds about 90,000 words.
The 500 questions were drawn at random from SQuAD, a reading-comprehension dataset whose questions were written about Wikipedia articles. all-MiniLM-L6-v2, the model Chroma uses by default, turned the paragraphs and the questions into vectors. Every database got the same vectors, and each returned 10 results per question.
The reference was an exact scan in numpy, a basic maths library, which compares each question with all 100,000 paragraphs and lists the ten closest. A returned paragraph counted as found when it sat no farther from the question than the tenth of those. That rule comes from ANN-Benchmarks, the standard test for these indexes. The data holds 125 duplicated paragraphs, and this way either copy counts.
One program built each database and a fresh one searched it, one question after another. The machine was an Apple M4 Max with 64 GB of memory, and it was running other jobs at the same time, so compare the times only roughly.
Each database ran in a sandbox, a locked box that keeps other people's code away from the rest of the machine. Milvus Lite's sandbox also had to allow network connections, because its own parts talk to each other that way.
This measures whether a database returns the nearest paragraphs. Whether those paragraphs answer the question depends on your embedding model and on how your text is cut.
Besides the main four, the table has five others. DuckDB is an analytics database, Zvec comes from Alibaba, FAISS is a search library from Meta, and Milvus Lite is a small version of the Milvus server. pgvector ran inside PGlite, a version of Postgres that runs without a server, so these times aren't those of a full Postgres server. "Flat" is Zvec's word for exact search.
| Database and setting | Nearest passages found | Typical time per question (median), 10,000 / 100,000 paragraphs | Peak memory |
|---|---|---|---|
| numpy (the reference, exact) | 100% | 0.12 / 1.2 ms | 226 MB |
| sqlite‑vec, exact | 100% | 3.9 / 37 ms | 77 MB |
| LanceDB, no index, exact | 100% | 2.4 / 9.0 ms | 701 MB |
| LanceDB, default index (IVF_PQ) | 49 to 51% | 1.2 / 2.2 ms | 212 MB |
LanceDB, same index, refine_factor(10) | 92 to 93% | 1.9 / 2.7 ms | 218 MB |
| Chroma, default index (HNSW) | 97.7% | 0.54 / 0.84 ms | 339 MB |
| Qdrant local mode, exact | 100% | 2.7 / 29 ms | 2,915 MB |
| DuckDB, no index, exact | 100% | 5.5 / 33 ms | 292 MB |
| DuckDB, HNSW | 96.2% | 0.71 / 1.1 ms | 629 MB |
| Zvec, flat, exact | 100% | 0.40 / 4.9 ms | 303 MB |
| Zvec, HNSW | 99.9% | 0.37 / 1.8 ms | 341 MB |
| FAISS, exact | 100% | 0.28 / 0.76 ms | 246 MB |
| FAISS, HNSW | 88.1% | 0.09 / 0.10 ms | 276 MB |
| pgvector in PGlite, no index, exact | 100% | 4.9 / 48 ms | 923 MB |
| pgvector in PGlite, HNSW | 94.5% | 0.88 / 1.3 ms | 954 MB |
| Milvus Lite, automatic index | 98.2% | 2.7 / 18 ms | 1,068 MB |
Versions: sqlite-vec 0.1.9, LanceDB 0.41.0, Chroma 1.5.9, qdrant-client 1.20.0, DuckDB 2.0.0, Zvec 0.8.0, faiss-cpu 1.15.1, PGlite 0.5.15 with pgvector 0.8.7, Milvus Lite 3.2.2, the latest releases that day. The two runs gave the same exact-search answers, and the times moved: sqlite-vec took 43 ms on 27 October and 37 ms on 4 November.
Below about 100,000 passages, skip the index
Under that size you can compare your question with every passage and never miss a nearest one. Every exact search returned the ten nearest paragraphs for all 500 questions. At 10,000 paragraphs, every database answered in under 6 ms. At 100,000, among full databases, exact search took between 5 ms (Zvec) and 48 ms (pgvector in PGlite) per question.
The time grows in step with your collection, and that gives you a yardstick. sqlite-vec took 37 ms at 100,000 paragraphs. It took 109 ms at 300,000 and 391 ms at a million, measured on random vectors on 4 November 2026. LanceDB's FAQ uses about 100 ms as its yardstick for an acceptable wait.
Here is the order of moves as your collection grows:
- Up to about 100,000 passages: sqlite-vec, no index. Each search takes a few dozen milliseconds.
- From there to about a million: sqlite-vec still works, and it depends on who is waiting. Each search takes 100 to 400 ms. For an answer an AI model then writes, that may be fine. If it isn't, ask your coding agent to move to LanceDB with an index.
- Past about a million: LanceDB with an index. Its FAQ says its open-source version "can comfortably handle millions of vectors on a single node", meaning one machine.
- Past about 10 million: a database on a server.
The makers say the same. Alex Garcia, who wrote sqlite-vec, said in an October 2024 interview on Probabl's Sample Space podcast that "if you only have 100,000 vectors, sqlite-vec will work just fine; a brute force search will probably work just fine". Around 20 million, he said, sqlite-vec "currently can't do it".
LanceDB's FAQ agrees: "For small datasets of ~100K records or applications that can accept ~100ms latency, a vector index is usually not necessary."
One developer reports the same on phones. HanClinto, who posts on the programmers' forum Hacker News, wrote in May 2024 of shipping a search on phones that compared more than 200,000 very small vectors on every camera frame. Cheap phones still managed 10 frames a second or more. Those vectors were far smaller than the ones here, so only the lesson carries over: "It's amazing how frequently brute-force is good enough."
So a notes app, a folder of PDFs or an agent's memory rarely needs an index at all.
To stay on sqlite-vec longer, you can shrink the vectors. Binary quantization keeps one bit per number instead of 32 bits, the four bytes each number normally takes. The stored vectors become 32 times smaller, which makes searches faster. It wasn't part of this page's test. sqlite-vec's documentation warns that you lose "a lot" of quality, and it checks the best candidates again on the full vectors to recover it.
If you add an index, check its default settings
Comparing your question with every passage never missed a nearest one. The index LanceDB builds with no options found about half of them. Building that index four times on 4 November gave 49 to 51%, the same as a build on 27 October with the previous version.
Comparing your question with every passage never missed a nearest one. The index LanceDB builds with no options found about half of them.
Your coding agent gets this index, called IVF_PQ, when it calls table.create_index() with no options. It compresses each vector to a 64th of its size, from 1,536 bytes to 24. At its default search settings, it also put the true nearest paragraph first for only about 40% of the questions.
One setting repairs most of it. refine_factor(10) makes each search fetch 10 times more candidates, then rank them again on the full vectors. That found 92 to 93% of the nearest paragraphs, for under 1 ms more per question. Searching more clusters changed nothing, so the loss comes from the compression.
LanceDB's own FAQ asks "Do I need to set a refine factor when using an index?" and answers "Yes". The default still doesn't set one. To get the 92%, tell your coding agent: "When you search the LanceDB index, set refine_factor to 10."
The other indexes tested lost less at their default settings:
| Index (default search setting) | Nearest passages found, 100,000 paragraphs | With a larger setting |
|---|---|---|
| Zvec HNSW | 99.9% | 99.9% (ef 200) |
| Milvus Lite, automatic index | 98.2% | 99.8% (ef 256), 18 ms |
| Chroma HNSW (ef_search 100) | 97.7% | 99.6% (ef_search 400), 2.1 ms |
| DuckDB HNSW (ef_search 64) | 96.2% | 99.0% (ef_search 256), 1.9 ms |
| pgvector HNSW (hnsw.ef_search 40) | 94.5% | 99.1% (ef_search 200), 3.5 ms |
| FAISS HNSW (efSearch 16) | 88.1% | 98.5% (efSearch 128), 0.30 ms |
| LanceDB IVF_HNSW_SQ (ef = 15) | 87.3% | 98.0% (ef 100), 1.6 ms |
An average hides the worst questions. DuckDB's default settings left 20 of the 500 questions with fewer than 8 of their 10 nearest paragraphs, and one with none. The misses fell mostly on weak matches: questions whose closest paragraph was already a poor match.
The one question Chroma and DuckDB kept missing even at high settings was "Who was Count of Melfi". No paragraph in those 100,000 mentions Melfi, and its nearest neighbours were about Craig Mello and the town of Melun.
So an HNSW index at 96 to 98% costs you less than the figure suggests. What it loses are mostly paragraphs that wouldn't have answered the question anyway. The compressed IVF_PQ index is different: it fell short on 463 of the 500 questions, good matches included.
The ANN-Benchmarks authors found that "very few of these algorithms can tune themselves to produce a particular recall value", recall being the share of nearest results found. The settings are left to you and your coding agent.
You can test your own index. Tell your coding agent: "Run 20 of my real questions through the index and through an exact search, then tell me what share of the results they have in common, as a percentage." An exact search matches itself at 100%. Below about 95%, ask it to raise the index's search setting, by this page's own rule of thumb.
Searching inside one document's or one customer's passages
Many apps search a slice of the data: one document, one product's help pages, last month's notes. A search limited to a small slice can come back empty, with no error, so it deserves its own test. A slice separates results, not access: anyone who can open the file can read all of it.
The slice is called a metadata filter, a condition on a detail stored next to each vector, such as customer = 7. A database can apply a filter in two ways. Pre-filtering keeps the passages that pass, then compares your question with those only. Post-filtering searches the index first, then throws away the results that fail the condition.
Each way has a cost, as Liana Patel and her co-authors at Stanford and UC Berkeley set out in a 2024 paper. Pre-filtering "scales poorly", meaning it gets slow when a large share of a big collection passes the filter. Post-filtering starts from the nearest vectors, which may fail the filter, so it has to widen the search to find enough that pass.
The test gave every paragraph a number from 0 to 99, standing for the customer or document it belongs to, and ran the 500 questions twice more. One filter kept 1% of the paragraphs (1,000 of them, about one customer's files) and the other kept half. A result counted as found when it passed the filter and was among the ten nearest paragraphs that pass.
| Database and setting | Filter keeps 1%: nearest passages found, median time | Filter keeps 50% | Time with no filter |
|---|---|---|---|
| sqlite‑vec, ordinary metadata column | 100%, 20 ms | 100%, 29 ms | 37 ms |
| sqlite‑vec, partition key | 100%, 0.4 ms | 100%, 21 ms | 40 ms |
| LanceDB, no vector index | 100%, 9.4 ms | 100%, 12 ms | 9.0 ms |
| LanceDB, no vector index, scalar index on the filter | 100%, 6.2 ms | 100%, 8.7 ms | 9.1 ms |
LanceDB, IVF_PQ index, refine_factor(10) | 96.1%, 3.4 ms | 93.9%, 4.1 ms | 2.7 ms |
| Chroma, HNSW | 99.98%, 30 ms | 98.8%, 70 ms | 0.84 ms |
| Qdrant local mode | 100%, 351 ms | 100%, 349 ms | 29 ms |
| DuckDB, no index | 100%, 1.5 ms | 100%, 16 ms | 33 ms |
| DuckDB, HNSW | 99.9%, 12 ms | 97.9%, 3.3 ms | 1.1 ms |
| Zvec, HNSW | 96.6%, 11 ms | 100%, 2.5 ms | 1.8 ms |
| pgvector in PGlite, no index | 100%, 16 ms | 100%, 34 ms | 48 ms |
| pgvector, HNSW, defaults | 4.0%, 1.3 ms | 92.5%, 1.3 ms | 1.3 ms |
pgvector, HNSW, hnsw.iterative_scan = relaxed_order | 96.1%, 15 ms | 92.7%, 1.3 ms | 1.4 ms |
No database returned a passage that broke the filter. Three things stand out.
Exact search stays exact, and its speed depends on how the data is laid out. A filtered exact search has fewer passages to compare, so it should take less time. DuckDB, which stores each column separately, went from 33 ms to 1.5 ms with the narrow filter. sqlite-vec with an ordinary metadata column only dropped to 20 ms. As Alex Garcia wrote when he released the feature in November 2024, "metadata filters need to visit every single row".
When the filter is a partition key, which stores each value's vectors together, the same search took 0.4 ms. Garcia recommends partition keys "for user IDs or document IDs" and for dates by year or month, with hundreds of vectors per value. Too many small partitions slow searches down. Other conditions, such as an exact date range, go in metadata columns, up to 16 per table.
The filter cost most in Chroma and Qdrant's local mode. Chroma went from 0.84 ms with no filter to 30 ms with the narrow one and 70 ms with the broad one. Qdrant's local mode went from 29 ms to about 350 ms, because its source code checks the condition point by point, in Python, on every search.
Those waits don't matter while you try out an idea. For a live app with filters, a third of a second per search is a reason to leave Qdrant's local mode. The narrow filter also slowed DuckDB's and Zvec's indexes, to 12 ms and 11 ms, which nobody would notice.
An index that filters after searching can come back nearly empty. pgvector's documentation gives the arithmetic: "If a condition matches 10% of rows, with HNSW and the default hnsw.ef_search of 40, only 4 rows will match on average." With a filter that keeps 1%, the test got 0.4 results per question on average. 335 of the 500 questions got no result at all, with no error. Raising ef_search to 200 still left 53 questions with nothing.
The problem was known. In September 2024, Avthar Sewrathan, who helps developers build AI apps on Postgres at Tiger Data, listed filtered-search accuracy among HNSW's "known problems", in a talk on 18 months of pgvector projects.
pgvector 0.8.0 answered it the next month with a setting called iterative index scans. The index then keeps scanning until enough passages pass, up to 20,000 visited by default. Every question got its 10 results, 96.1% of them among the nearest, in 15 ms. Tell your coding agent: "Set hnsw.iterative_scan to relaxed_order." pgvector's documentation first suggests an ordinary index on the filter column, which wasn't part of the test.
Andrei Vasnetsov, co-founder of Qdrant, explained in 2019 why HNSW's map struggles with filters. Remove the entries that fail a filter and the map breaks into pieces, so the walk towards your question can't reach the passages that pass. The HNSW indexes other than pgvector's returned 10 results every time and lost little: Chroma kept 98.8% at the broad filter, DuckDB 97.9%, Zvec 96.6% at the narrow one.
LanceDB filters before searching by default ("Pre-filtering is enabled by default", its documentation says). The same page says: "We strongly recommend creating scalar indices on columns used for filtering." A scalar index is an ordinary index on that column. In both test runs, it took the narrow search from about 9 ms to about 6 ms.
When you filter, ask your coding agent to report two numbers on your own questions: the share of nearest results found, and how many results came back. A post-filtering index fails quietly, by returning fewer results.
When two programs open the database at once
A common setup has two programs: your app, which keeps the database open, and a small program that adds new documents. Here the databases differ most. The test reproduced it. Program A opened each database with 2,000 passages and searched it. Program B then opened the same database, added one passage and exited. Program A then searched for that passage.
| Database | Can B write while A is open? | Does A find the new passage? | After A reopens, or in a new program |
|---|---|---|---|
| sqlite‑vec | Yes | Yes, at once | Yes |
| LanceDB, default | Yes | No: A still counts 2,000 passages | Yes |
LanceDB, read_consistency_interval=timedelta(0) | Yes | Yes, at once | Yes |
| Chroma | Yes | No, though its count shows 2,001 | Not after reopening. Yes in a new program |
| Qdrant local mode | No: "Storage folder … is already accessed by another instance of Qdrant client" | Not applicable | Not applicable |
| DuckDB (whether A opened it for writing or read‑only) | No: "Could not set lock on file" | Not applicable | Not applicable |
| Zvec (whether A opened it for writing or read‑only) | No: "Can't lock read-write collection" | Not applicable | Not applicable |
Chroma accepted the write, then program A never found the passage. That held even when program A opened the folder again, because Chroma reuses one open connection per folder inside a program. Only a fresh program found it, or one that clears Chroma's internal cache first.
A builder reported this very setup in February 2025 on GitHub, where people report software problems: a web interface left running, plus scripts that admins use to update the database. The new documents showed up when listed and never in search.
Chroma's makers answered there. Hammad Bashir, its CTO, wrote: "local chroma is not process safe. We don't intend to support usage across processes in the near term… There is in memory state that will not be reflected in the second process." Trayan Azarov, a long-time contributor, added that this way of storing data "can lead to corruption and data loss". A process is a running program, so this rules out two programs on one folder.
Another report, opened in May 2026 and still open, describes a second program waiting about 16 minutes when two open the same folder at once, because the first holds it locked. Chroma's makers advise running Chroma as a server (chroma run), with both programs connecting to it.
LanceDB keeps every write as a new version of the table, and an open table keeps reading the version it opened. That is why program A misses the new passage. Connecting with read_consistency_interval=timedelta(0) makes each read check for a newer version, at a small cost per read. LanceDB also accepts several writing programs, though its FAQ warns that "too many concurrent writers can lead to failing writes".
sqlite-vec needs no setting for program A to find the new passage, as the table shows. Only one program can write at a time: SQLite says "there can only be one writer at a time", so a second one waits its turn. Every program must also be on the same machine.
One setting is worth adding for a live app: WAL mode. It stands for write-ahead log: new data goes to a second file beside the database, so searches and writes wait less for each other.
A further test had one program searching 100,000 random vectors in a loop while another added 1,000 vectors every second. No search failed, in either mode. Each write took 38 ms by default and 11 ms in WAL mode, and the slowest search took 83 ms and 57 ms.
To switch it on, tell your coding agent: "Turn on WAL mode for the SQLite file." It takes one line. WAL "will not work on a network filesystem", so the file has to stay on the computer's own disk. And because recent writes sit in that second file, ask your coding agent to use SQLite's backup command rather than copying the file while your app runs.
Qdrant's local mode, DuckDB and Zvec lock out a second writing program. DuckDB lets several programs read in read-only mode, but none can write meanwhile. To write from several programs, DuckDB 2.0 offers Quack, a way of reaching DuckDB over a network. Its documentation says this "turns DuckDB into a client-server database", meaning a server that programs connect to. Qdrant's answer is its server.
Which programming languages can open the file
Your coding agent may fill the database from a Python script while your app is written in JavaScript, so the data has to open in both. In the test, Python wrote a sqlite-vec file and a LanceDB table of 10,000 paragraphs. Node.js 24, which runs JavaScript on a computer, then opened each one. Both returned the same ten paragraphs in the same order as Python, for 50 questions out of 50.
| Database | Languages, per its documentation (4 Nov 2026) |
|---|---|
| sqlite‑vec | Python, Node.js (and Deno, Bun), Go, Rust, Ruby, and browsers |
| LanceDB | Python, TypeScript (a stricter form of JavaScript), Rust |
| Chroma (built‑in mode) | Python. "To connect with the JS/TS client, you must connect to a Chroma server" |
| Qdrant local mode | Python only, being a feature of the Python client |
| Zvec | Python, Node.js, Go, Rust, Java, Dart/Flutter |
| DuckDB | Python, R, Java, Node.js, Go, Rust and others |
One trap on Macs: sqlite-vec loads into Python's built-in SQLite, and some Python installs can't load add-ons. Your coding agent would then report this error: 'sqlite3.Connection' object has no attribute 'enable_load_extension'.
On 27 October 2026, the Python from python.org and Apple's own Python both failed this way on the test Mac. A Hacker News reader hit the same wall with a third install. sqlite-vec's Python guide suggests Homebrew's Python, Homebrew being a common Mac installer, and that one worked on the test Mac.
What each one takes on your computer
What a database takes on your computer varies widely, from 188 KB to 351 MB just to install. Packages, in this table, are the separate pieces of software an install brings with it.
| Database | Installed, with what it needs (macOS; Python 3.13 unless noted) | Time to load 100,000 paragraphs | On disk, with 154 MB of vectors (100,000 × 1,536 bytes) |
|---|---|---|---|
| sqlite‑vec | 188 KB, one package | 1.0 s | 206 MB |
| DuckDB | 52 MB, plus a 40.5 MB extension downloaded the first time | 1.9 s | 185 MB (352 MB with HNSW) |
| Zvec | 51 MB, two packages | 2.5 s (16 s with HNSW) | 210 MB (248 MB with HNSW) |
| Qdrant client | 81 MB, 20 packages | 53 s | 521 MB |
| Milvus Lite | 274 MB, 20 packages | 8.8 s | 351 MB |
| LanceDB | 330 MB, 16 packages | 0.8 s (3.1 s with IVF_PQ) | 180 MB (184 MB with IVF_PQ) |
| Chroma | 351 MB, 84 packages, including what runs its embedding model | 39 s | 526 MB |
| FAISS | 42 MB, 3 packages | 0.03 s (1.4 s with HNSW) | 154 MB (182 MB with HNSW), vectors only |
| pgvector in PGlite | 27 MB, two packages (Node.js) | 42 s (92 s with HNSW) | 379 MB (782 MB with HNSW), about half of it Postgres's log |
Only Chroma's install includes an embedding model's software. The others need some added. fastembed, which runs the same all-MiniLM-L6-v2 model, adds 148 MB and 28 packages. It gave the same vectors as sentence-transformers, the better-known option, on five test sentences, and sentence-transformers adds 876 MB and 41 packages. So sqlite-vec with fastembed comes to about 148 MB, against 351 MB for Chroma. The model itself downloads the first time, about 90 MB.
Chroma's data took 526 MB of disk: about 353 MB for a SQLite file that holds the documents, their details and a full-text index of every document, plus 173 MB of index files. Chroma's documentation says each collection is indexed "for vector similarity, full-text search, and metadata filtering", whether or not you use the last two.
Qdrant's local mode keeps every passage in Python's memory: 2.9 GB to search 100,000 passages, 3 seconds to open the folder, and a warning printed by its own software: "Local mode is not recommended for collections with more than 20,000 points." Points are its word for passages. sqlite-vec's searching program peaked at 77 MB, because it reads the vectors from the file as it scans.
So Qdrant's local mode is for trying things out. An app that wants Qdrant on one machine runs the full server: RecurseChat, a Mac app for chatting with AI models on your machine, chose that in 2024.
The other local options: DuckDB, Zvec, Milvus Lite, pgvector, FAISS
These five come up often in lists of local databases. Each fits a narrower case than sqlite-vec, LanceDB, Chroma or Qdrant's local mode, so here is when each one makes sense.
DuckDB makes sense if you already analyse your data in it. It is an analytics database that runs inside your program. Exact search worked well (33 ms at 100,000 paragraphs). It isn't a main pick because a second program can't write while the first is open, and its HNSW index is experimental.
Storing that index on disk needs an experimental setting. Its documentation warns that a crash with unsaved changes can mean "data loss or corruption of the index", advises against live use, and says the index must fit in memory.
Zvec makes sense for one program that wants a fast index with no tuning. It comes from Alibaba, and its HNSW index found 99.9% of the nearest passages at default settings, the best of the indexes tested.
Zvec isn't a main pick because it is young: it was open-sourced in December 2025. Only one program can write, too. Its project page says "multiple processes can read the same collection simultaneously; writes are single-process exclusive", and the test confirmed the second half.
Milvus Lite makes sense if your app will later move to a Milvus server. Milvus is a vector database normally run as a server, and Milvus Lite is its small version, which runs inside a Python program. It found 98.2% of the nearest passages in 18 ms per question and used about 1.1 GB of memory. Its project page limits it to one program per data folder.
pgvector makes sense if your app already runs on Postgres. It searches exactly by default, "which provides perfect recall", and adds indexes on request: HNSW, or IVFFlat, its index of the IVF kind.
Postgres on your computer counts as self-hosted, since it is a server program. PGlite is local: it runs pgvector inside Node.js or a browser with no server at all. In the test (PGlite 0.5.15, pgvector 0.8.7), exact search took 48 ms per question at 100,000 paragraphs, close to sqlite-vec. Its HNSW index found 94.5% of the nearest passages at its default setting, and 99.1% with that setting raised.
The PGlite program used about 1 GB of memory. With a narrow filter, the default HNSW search returned nothing for two questions in three, until iterative index scans were switched on. If you run an older pgvector, ask your coding agent to update it to 0.8.7 or later. That release, of 1 October 2026, fixed a security flaw in how IVFFlat indexes are built.
FAISS makes sense if your coding agent already stores your text somewhere else. It comes from Meta, and it describes itself as "a library for efficient similarity search and clustering of dense vectors": it finds the nearest vectors and nothing else.
Its exact index searched 100,000 vectors in 0.8 ms per question, from one 154 MB file. Its HNSW index found 88.1% of the nearest passages at its default setting and 98.5% with it raised. It keeps only vectors and ID numbers, so your code must keep the text and apply any filter.
Two more names appear on Google for this search: Annoy and hyperDB. Annoy comes from Spotify, the music service, and a tutorial on Hugging Face, a site for sharing AI models, uses it to build a local index. Its last release on PyPI, Python's package store, dates from June 2023.
hyperDB describes itself as "a hyper-fast local vector database", and its last release dates from July 2023. Neither was tested here. With no release in over three years, neither is a good place to start.
What changes your results more than the database
Switching databases rarely fixes bad answers. Chroma's, DuckDB's and Zvec's indexes found 96 to 99.9% of the nearest paragraphs at their default settings, and every HNSW index tested reached 98 to 99.9% with one setting raised. What decides whether those paragraphs answer the question comes earlier: your embedding model and the way your text is cut into passages.
Chroma's own research report on this, by Brandon Smith and Anton Troynikov (July 2024), measured how much of the text that answers a question reached the top 5 passages, over 472 questions. With OpenAI's large embedding model, scores ran from 83.6% to 91.9%, depending on how the text was cut. With all-MiniLM-L6-v2, the small model used in this page's test, they ran from 75.2% to 82.4%.
On the three ways of cutting tested with both models, the small model scored 10 to 12 percentage points lower. With one model, the way of cutting moved the score by up to 8 points. Both gaps are larger than what Chroma's, DuckDB's or Zvec's index lost at its default settings: 4 points at most.
So when answers disappoint, change these two things before you change database. For a larger model that still runs on your computer, ask your coding agent to try all-mpnet-base-v2, which its makers say "provides the best quality" of their general models. For the cutting, Chroma's report found passages of about 200 tokens, roughly 150 words, cut at paragraph and sentence breaks, consistently good. With an online model, your text goes to its maker.
Chang She, LanceDB's chief executive, ranks these causes the same way in a 2025 talk: what your data looks like, how it is encoded, what the user means, and last, "the least important", the search techniques.
Names, codes and rare words are where a keyword index next to the vectors helps, and Chroma's CTO pairs the two in one search for that case. FTS5 sits in the same file as sqlite-vec, and LanceDB and Chroma have keyword indexes of their own.
How to set it up: what to ask your coding agent
Your coding agent can do all of this. Give it this request, with your own documents and questions in it:
Add search by meaning to this project with sqlite-vec. My documents are in [where your documents are]. Cut them into passages of about 150 words, at paragraph breaks. Turn each passage into a vector with the all-MiniLM-L6-v2 model, through fastembed or its equivalent for this project's language, running on this computer and not through an online service. Keep the passages and their vectors in one SQLite file, with WAL mode on. Then run these questions and show me the first three passages returned for each: [your questions].
Then read what comes back. You know your documents, so you can tell at a glance whether the passages answer your questions. If they don't, try a larger model or another way of cutting.
The rest of this chapter is for your coding agent, if it gets stuck: paste it into your conversation. The code runs as written on most Python installs after pip install sqlite-vec fastembed. recall() gives 1.0 here, because sqlite-vec compares the question with every passage. It is there to check a search again if you later add an index.
import sqlite3, sqlite_vec, numpy as np
from fastembed import TextEmbedding
model = TextEmbedding("sentence-transformers/all-MiniLM-L6-v2") # 384 numbers per text
def embed(items):
return np.array(list(model.embed(items)), dtype=np.float32)
texts = ["Reset your password from the login page, under Forgot password.",
"Invoices are emailed on the first day of each month."]
vecs = embed(texts)
db = sqlite3.connect("notes.db")
db.execute("pragma journal_mode=wal") # searches and writes wait less for each other
db.enable_load_extension(True)
sqlite_vec.load(db)
db.enable_load_extension(False)
db.execute("create table if not exists chunks(id integer primary key, body text)")
db.execute("create virtual table if not exists vec_chunks "
"using vec0(embedding float[384] distance_metric=cosine)")
with db:
for i, (text, vec) in enumerate(zip(texts, vecs), start=1):
db.execute("insert or replace into chunks values (?, ?)", (i, text))
db.execute("insert or replace into vec_chunks(rowid, embedding) values (?, ?)", (i, vec.tobytes()))
def search(q, k=10):
return db.execute(
"select c.id, round(v.distance, 3), substr(c.body, 1, 60) "
"from vec_chunks v join chunks c on c.id = v.rowid "
"where v.embedding match ? and k = ? order by v.distance",
(q.tobytes(), k)).fetchall()
def recall(q, k=10):
exact = {int(i) + 1 for i in np.argsort(-(vecs @ q))[:k]} # rowids start at 1
return len(exact & {row[0] for row in search(q, k)}) / len(exact)
q = embed(["How do I change my password?"])[0]
print(search(q, k=2), recall(q, k=2))
If you change model, ask your coding agent to match float[384] to the count of numbers the new model returns, and to embed questions with the model that embedded the passages.
Here is the same data in LanceDB, with the two settings from the test: one on the connection and one on each search. bypass_vector_index() gives the exact answer to compare with once you have built an index. This block and the next use the variables of the first.
import lancedb
from datetime import timedelta
ldb = lancedb.connect("lance_data", read_consistency_interval=timedelta(0)) # see other programs' writes
tbl = ldb.create_table("chunks", [{"id": i, "text": t, "vector": v}
for i, (t, v) in enumerate(zip(texts, vecs), start=1)], exist_ok=True)
fast = tbl.search(q).distance_type("cosine").limit(10).refine_factor(10).to_list()
exact = tbl.search(q).distance_type("cosine").limit(10).bypass_vector_index().to_list()
To keep each search inside one document's passages, give the vectors a partition key:
db.execute("create virtual table if not exists vec_by_doc using vec0("
"doc_id integer partition key, embedding float[384] distance_metric=cosine)")
with db:
for i, (doc_id, vec) in enumerate(zip([1, 2], vecs), start=1): # the document each passage came from
db.execute("insert or replace into vec_by_doc(rowid, doc_id, embedding) values (?, ?, ?)",
(i, doc_id, vec.tobytes()))
print(db.execute("select rowid, round(distance, 3) from vec_by_doc "
"where embedding match ? and k = 10 and doc_id = ? order by distance",
(q.tobytes(), 2)).fetchall()) # searches document 2 only
In LanceDB the same filter is .where("doc_id = 2") on the search. An ordinary index on that column speeds it up: create_index("doc_id", config=BTree()). LanceDB flags the older create_scalar_index as deprecated.
When a local file is the wrong choice
A local database is one file or folder that programs on one machine open directly. Move to a server when any of these is true:
- Your code runs as serverless functions. These are small programs an online host starts and stops on demand, and your coding agent can tell you whether your app runs this way. AWS, Amazon's hosting service, describes the storage of its Lambda functions as "temporary and unique to each execution environment". Each copy of your function would hold its own database and lose it.
- More than one machine writes, or the file sits on a network drive. SQLite's WAL mode "will not work on a network filesystem". Qdrant's local mode, DuckDB and Zvec lock their folder to one writing program. LanceDB is the exception here: it can keep its tables on online file storage.
- Several programs must write and the database is Chroma, Qdrant's local mode, DuckDB or Zvec. All four keep writes to one program: Chroma on its makers' advice, the other three with a lock.
- Different users must see different data. A file has no logins or permissions of its own, so any program that can read it reads all of it. Filters separate results, not access.
- Your collection heads past about 10 million vectors. sqlite-vec's author puts its exact search out of reach around 20 million. LanceDB's FAQ says its open-source version can handle millions on one machine. Chroma sizes its single-server mode at "typically fewer than 10 million records".
To move to a server, ask your coding agent for the matching route: chroma run for Chroma, the Qdrant server in Docker, pgvector in your Postgres, or DuckDB's Quack. sqlite-vec has no server of its own, so the usual move is to pgvector. LanceDB can keep its tables on online file storage compatible with Amazon's S3, which suits functions that only read.
If you are building a product to sell, starting a SaaS with AI covers the rest of that path.
FAQ
Is there any free vector database? Yes: every local database on this page is free and open source, including sqlite-vec, LanceDB, Chroma, Qdrant, DuckDB, FAISS and pgvector. You pay only in disk space and memory when you run one on your own computer. Online services such as Pinecone charge for hosting one.
What are the top 5 vector databases? It depends on what "top" measures. DB-Engines, a site that ranks databases by popularity, lists in November 2026 among products built only for vectors: Pinecone, Qdrant, Milvus, Weaviate and Chroma. Those five are server or online products, and Qdrant and Chroma also have the local modes covered here. For a local one, start with sqlite-vec, LanceDB, Chroma and Qdrant's local mode, plus Zvec, whose index came out best in this page's test.
Does ChatGPT use a vector database? OpenAI doesn't say what runs inside ChatGPT itself, in the documentation read on 4 November 2026. Its developer documentation does describe "vector stores": you upload files, and its File Search tool retrieves from them "through semantic and keyword search". OpenAI hosts those stores, so this is the opposite of a local database.
Is the vector database outdated? No, but it has lost its place as the only way to search. Claude Code does without one, Cursor gets better results by adding one to text search, and keyword search beat vector search on a test of made-up company documents. For a collection too large for an agent to read, where people ask in their own words, a vector database next to a keyword search still does the job.
Which local vector database is best for RAG? sqlite-vec is the safest start for RAG, where an AI model answers from passages your program fetches. sqlite-vec, LanceDB, Chroma and Qdrant's local mode all return the nearest passages when they compare with every passage, up to about 100,000. With an index, check its settings. Then spend your effort on the embedding model and on how your text is cut, which moved results more in Chroma's report than an index lost in this page's test.
Is FAISS a vector database? Not by its own description: FAISS is "a library for efficient similarity search and clustering of dense vectors". It finds the nearest vectors fast (0.8 ms per question over 100,000 vectors in the test, exact). Storing the text and the details, and filtering on them, is your code's job. Its HNSW index also ships with a low search setting: 88.1% of the nearest passages at its default.
Can pgvector run locally without a server?
Yes, through PGlite, a version of Postgres that runs inside a Node.js program or a browser. In the test it searched 100,000 vectors exactly in 48 ms per question. Ordinary Postgres, on your machine or in Docker, is self-hosted: it runs as a server program. pgvector's HNSW index needs hnsw.iterative_scan set once you filter, or narrow filters return too few results.
How do I search only one document's or one customer's passages? Store the document or customer number next to each vector and filter on it in the search itself. sqlite-vec takes it as a partition key: in the test, a search limited to 1% of 100,000 paragraphs took 0.4 ms, against 20 ms with an ordinary metadata column. A filter separates results, not access: anyone who can open the file can read all of it, so customers who log in need a server.
Does Chroma work in JavaScript or TypeScript without a server? No. Chroma's documentation says "to connect with the JS/TS client, you must connect to a Chroma server", so its built-in mode is Python only. A JavaScript app can use LanceDB's TypeScript package or sqlite-vec's npm package instead. Both open the data a Python script wrote.
How many vectors can sqlite-vec handle? Its stable version has no index, so it compares your question with every vector. Its author considers 100,000 vectors "just fine" and says it "currently can't do it" around 20 million. In the test it took 37 ms per question at 100,000, 109 ms at 300,000 and 391 ms at a million. Indexes exist only in the 0.1.10 alpha releases of March to May 2026, test versions not meant for your live app.
Is DuckDB a vector database?
It is an analytics database that can also store vectors and search them exactly. Its HNSW index comes from an extension called vss, which DuckDB calls experimental. Storing that index on disk requires an experimental setting its documentation advises against for live use.
Chroma or Qdrant for a local prototype? Locally, they are different kinds of software. Chroma's built-in mode uses an HNSW index and brings its own embedding model. Qdrant's local mode is an exact scan written in Python that imitates the Qdrant server: it used 2.9 GB of memory for 100,000 passages in the test and warns above 20,000. Choose Qdrant's local mode when your code will move to a Qdrant server, Chroma when it should start fast in one program.
How does a local vector database differ from a self-hosted one? A local one runs inside your program and reads and writes a file or folder on your disk. A self-hosted one is a database server you run yourself, on your machine or a rented one, that programs reach over a network. The second handles several machines and many writers. The first adds no separate program to run, update or secure.
Sources (64)
The exact pages the facts above come from, with the date each was published or read.
- sqlite-vec: README and releases (v0.1.9, v0.1.10 alphas)Alex Garcia on GitHub, Nov 4, 2026
- OpenClaw memory configuration (sqlite-vec, on by default)OpenClaw docs, Nov 4, 2026
- OpenClaw memory search (embeddings and keywords)OpenClaw docs, Nov 4, 2026
- Vector Databases (LanceDB built in)AnythingLLM docs, Nov 4, 2026
- How LanceDB Supercharged Our Knowledge GraphDosu, Aug 4, 2025
- pgvector: Embeddings and vector similaritySupabase docs, Nov 4, 2026
- Claude Code: Anthropic's agent in your terminal (Boris Cherny, Cat Wu)Latent Space, 2025
- Improving agent with semantic searchCursor, Nov 6, 2025
- rip vector databaseturbopuffer, Sep 30, 2026
- EnterpriseRAG-Bench: A RAG Benchmark for Company Internal KnowledgeSun et al., Onyx (arXiv), May 5, 2026
- BrowseComp-Plus: A More Fair and Transparent Evaluation Benchmark of Deep-Research AgentChen et al. (arXiv), Aug 8, 2025
- BM25 Wins at Scale: A Scaling Study of Retrieval-Augmented Generation ParadigmsZhang et al. (arXiv), Jul 29, 2026
- Simple English Wikipedia dump of 1 November 2023 (wikimedia/wikipedia, 20231101.simple)Wikimedia on Hugging Face, Nov 1, 2023
- SQuAD 1.1 (validation questions)Stanford, on Hugging Face, 2016
- all-MiniLM-L6-v2Sentence Transformers on Hugging Face, Nov 4, 2026
- ANN-Benchmarks: A Benchmarking Tool for Approximate Nearest Neighbor AlgorithmsAumüller, Bernhardsson, Faithfull (arXiv), Jul 17, 2018
- Sqlite can totally do embeddings now, with Alex Garcia (Sample Space podcast)Probabl on YouTube, Oct 23, 2024
- Frequently asked questions (refine factor, index thresholds, concurrency)LanceDB docs, Nov 4, 2026
- I'm writing a new vector search SQLite Extension (HanClinto's comment)Hacker News, May 3, 2024
- Binary quantizationsqlite-vec docs, Nov 4, 2026
- Vector indexes (build and search parameters)LanceDB docs, Nov 4, 2026
- Configure collections (HNSW defaults)Chroma docs, Nov 4, 2026
- ACORN: Performant and Predicate-Agnostic Search Over Vector Embeddings and Structured DataPatel, Kraft, Guestrin, Zaharia (SIGMOD 2024, arXiv), Mar 7, 2024
- sqlite-vec now supports metadata columns and filtering (v0.1.6)Alex Garcia, Nov 20, 2024
- vec0 virtual tables: metadata, partition keys, auxiliary columnssqlite-vec docs, Nov 4, 2026
- Metadata filtering (where filters)Chroma docs, Nov 4, 2026
- qdrant-client local mode source (payload filters checked point by point)Qdrant on GitHub, Nov 4, 2026
- pgvector READMEpgvector on GitHub, Nov 4, 2026
- pgvector 0.8.0 released (iterative index scans)PostgreSQL News, Nov 11, 2024
- 18 Months of Pgvector Learnings in 47 Minutes (Avthar Sewrathan)Tiger Data on YouTube, Sep 26, 2024
- Filterable HNSW Without Recall Loss (the 2019 design of filtered HNSW search)Andrei Vasnetsov, Qdrant, 2019
- Filtering (pre-filtering, post-filtering, scalar indexes)LanceDB docs, Nov 4, 2026
- Issue #3792: Query does not match Get on persistent DB accessed by two processesChroma on GitHub, Feb 16, 2025
- Issue #7040: PersistentClient second-opener hangs about 16 minutes on a shared persist_dirChroma on GitHub, May 10, 2026
- Issue #2399: query after add does not use updated dbChroma on GitHub, Jun 21, 2024
- Client-server mode (chroma run)Chroma docs, Oct 27, 2026
- Consistency (read_consistency_interval)LanceDB docs, Nov 4, 2026
- Write-Ahead LoggingSQLite, Nov 4, 2026
- ConcurrencyDuckDB docs, Nov 4, 2026
- Clients (the JavaScript client needs a server)Chroma docs, Nov 4, 2026
- Sqlite-vec: a vector search SQLite extension that runs anywhere (a reader's report on pyenv)Hacker News, Aug 2, 2024
- Using sqlite-vec in Pythonsqlite-vec docs, Nov 4, 2026
- Architecture overview (local, single-node, distributed)Chroma docs, Nov 4, 2026
- qdrant-client local mode source (20,000-point warning, folder lock)Qdrant on GitHub, Nov 4, 2026
- qdrant-client README (local mode)Qdrant on GitHub, Nov 4, 2026
- Local Docs, Local AI: Chat with PDF locally using Llama 3RecurseChat, Apr 27, 2024
- Vector Similarity Search extension (vss)DuckDB docs, Nov 4, 2026
- Zvec README (v0.8.0)Alibaba on GitHub, Nov 4, 2026
- Milvus Lite README (known limitations)Milvus on GitHub, Nov 4, 2026
- PGlite extensions (pgvector)PGlite, Nov 4, 2026
- pgvector changelog (0.8.7: IVFFlat index build fix)pgvector on GitHub, Nov 4, 2026
- fastembedPyPI, Nov 4, 2026
- Faiss READMEMeta on GitHub, Nov 4, 2026
- Building a Local Vector Database Index with Annoy and Sentence TransformersHugging Face, community article, Nov 4, 2026
- annoy, by SpotifyPyPI, Nov 4, 2026
- hyperDBjdagdelen on GitHub, Nov 4, 2026
- Pretrained models (all-mpnet-base-v2 and all-MiniLM-L6-v2)Sentence Transformers docs, Nov 4, 2026
- Evaluating Chunking Strategies for RetrievalChroma Research (Smith, Troynikov), Jul 3, 2024
- The Art of Production Quality Retrieval (Chang She, LanceDB)The Linux Foundation on YouTube, Sep 9, 2025
- Building search for AI systems with Chroma CTO Hammad BashirDatabase School on YouTube, Dec 18, 2025
- Configure ephemeral storage for Lambda functionsAWS docs, Nov 4, 2026
- Storage configuration (S3-compatible object storage)LanceDB docs, Nov 4, 2026
- DB-Engines ranking of vector DBMS (November 2026)DB-Engines, Nov 4, 2026
- File search (vector stores)OpenAI docs, Nov 4, 2026
This guide gives general information, version of November 4, 2026: for a decision that commits you, ask a professional.
Read next
All Build guides- Updated November 4, 202637 minBest Mac Mini for OpenClaw: Which to Buy, or None (2026)Best Mac mini for OpenClaw: which M6 to buy at November 2026 prices, when to buy none, and what it takes to bring your agent back after a power cut.
- Updated November 4, 202640 minOpenClaw MCP Server: How to Add One, Step by Step (2026)How to add an OpenClaw MCP server, tested on version 2026.10.10: stop the Gateway or use the Settings form, check your agent gets the tools, then limit them.
- Updated November 4, 202625 minCursor Student Discount: It Ended, What's Free Now (2026)Cursor's free year of Pro for students closed on 25 June 2026. What's free now: Cursor's free plan and credits, then GitHub, Google and OpenAI student offers.
- Updated November 4, 202646 minAI Agents Integration: The Guide, With or Without Code (2026)AI agents integration: no-code connectors in Claude and ChatGPT, three ways to connect your own agent, platforms and prices, 35 MCP servers tested.
Save months!
Get free tips tested on real projects, by email.