
Photo: Pachon in Motion / Pexels
No Server, No Docker: LanceDB Is the Disk-Persisted Vector Store Your RAG Pipeline Has Been Missing
Chris Harper
3 min read
Aug 14, 2026 · 04:19 UTC
LanceDB is an embedded vector database that persists to disk like a file — no server, no Docker, and native hybrid (vector + BM25 keyword) search built in.
You've seen the vector store spectrum already: FAISS is blazing fast but resets on restart; Chroma persists to disk and has a great developer API; pgvector integrates with your existing Postgres. LanceDB fills a distinct gap: fully embedded (no server process), automatic disk persistence in the Apache Lance columnar format, and hybrid search — vector similarity plus BM25 keyword — built in without extra infrastructure.
Think of it as the DuckDB of vector stores: embed it in your process, close the connection, reopen it next week, and your indexed embeddings are exactly where you left them.
Install
pip install lancedb sentence-transformers
Connect and populate
import lancedb
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("all-MiniLM-L6-v2") # 384-dim, no API key needed
# creates ./rag_db/ on first call; subsequent calls reopen the same store
db = lancedb.connect("./rag_db")
docs = [
{"id": "doc-1", "text": "LanceDB stores vectors alongside any metadata column", "source": "docs"},
{"id": "doc-2", "text": "Hybrid search blends vector similarity with BM25 keyword ranking", "source": "blog"},
{"id": "doc-3", "text": "The Lance columnar format enables fast filtered scans over billions of rows", "source": "blog"},
]
rows = [{**d, "vector": model.encode(d["text"]).tolist()} for d in docs]
table = db.create_table("knowledge", data=rows, mode="overwrite")
Vector search
query = "how does column storage help retrieval?"
q_vec = model.encode(query).tolist()
results = (
table.search(q_vec)
.metric("cosine")
.limit(3)
.select(["id", "text", "_distance"])
.to_pandas()
)
print(results)
Hybrid search (vector + BM25)
from lancedb.rerankers import RRFReranker
# build the BM25 full-text index once; persists to disk with the table
table.create_fts_index("text")
results = (
table.search(
"columnar storage retrieval",
query_type="hybrid",
vector_column_name="vector",
fts_columns="text",
)
.rerank(RRFReranker()) # Reciprocal Rank Fusion blends both lists
.limit(3)
.to_pandas()
)
RRF promotes any result that ranks highly in both vector and keyword lists — a result that appears in position 3 of the vector results and position 2 of the BM25 results floats to the top.
Metadata filtering
# SQL WHERE clause on any column, combined with vector search
results = (
table.search(q_vec)
.where("source = 'docs'") # prune before ranking
.limit(5)
.to_pandas()
)
ANN index for large tables
Once your table exceeds ~100K rows, add an approximate nearest-neighbor index so search stays sub-millisecond:
table.create_index(metric="cosine", vector_column_name="vector")
Vector store comparison
| FAISS | Chroma | LanceDB | pgvector | |
|---|---|---|---|---|
| Embedded (no server) | Yes | Yes | Yes | No |
| Auto disk persistence | No (manual save) | Yes | Yes | Yes |
| Hybrid search built-in | No | No | Yes (BM25 + RRF) | Partial |
| Metadata filter | No | Yes | Yes (SQL) | Yes (SQL) |
| Production path | Self-manage | Chroma Cloud | LanceDB Cloud | Managed Postgres |
From local to cloud
When you're ready to scale beyond a single machine, point at LanceDB Cloud — the same table, index, and search code works unchanged, you just swap the connection URI. No rewrite required.
Sources: LanceDB documentation · Full-Text Search — LanceDB docs · Hybrid Search — LanceDB docs · lancedb/lancedb — GitHub