
FAISS: Build a Lightning-Fast Local Vector Index in 15 Lines of Python
Chris Harper
3 min read
Aug 11, 2026 · 20:03 UTC
FAISS is Meta's open-source library for searching millions of embeddings in milliseconds — pure in-memory, no server required, and the backbone of many production RAG systems.
What you'll be able to do after this:
- Build an exact-search vector index (
IndexFlatL2) and query it in two lines of Python - Switch to approximate-search (
IndexIVFFlat) when your dataset grows past ~100K vectors, with configurable speed/recall trade-off - Save and reload a FAISS index to disk so your embeddings survive restarts
FAISS vs. the alternatives. pgvector lives inside Postgres; Chroma is a persistent managed store. FAISS is neither — it's a raw, in-memory C++ library with Python bindings. That makes it the fastest option for search-heavy workloads where you control the lifecycle, and the best tool for learning how vector similarity actually works under the hood before adding a database layer.
Two indexes every ML engineer should know:
| Index | How it works | Best for |
|---|---|---|
IndexFlatL2 | Brute-force L2 distance over all vectors | <100K vectors; always exact |
IndexIVFFlat | Partitions space into nlist cells; searches nprobe cells per query | 100K–100M vectors; ~1% recall trade-off for 10–100× speed |
Walk-through
Install:
pip install faiss-cpu sentence-transformers numpy
Step 1: Exact search with IndexFlatL2
import faiss
import numpy as np
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("all-MiniLM-L6-v2")
docs = [
"Claude Code runs agentic sessions in your terminal",
"FAISS is a C++ library for fast vector similarity search",
"Embeddings encode meaning as high-dimensional float arrays",
]
doc_vecs = model.encode(docs, normalize_embeddings=True).astype("float32")
d = doc_vecs.shape[1] # 384 for MiniLM
index = faiss.IndexFlatL2(d) # exact L2 distance
index.add(doc_vecs) # add all vectors
print(index.ntotal) # 3
query = model.encode(["vector similarity library"], normalize_embeddings=True).astype("float32")
D, I = index.search(query, k=2) # top-2 results
print([docs[i] for i in I[0]]) # → ["FAISS is a C++ library…", "Embeddings encode…"]
Step 2: Approximate search with IndexIVFFlat for large datasets
nlist = 100 # cluster count (rule of thumb: sqrt(N))
quantizer = faiss.IndexFlatL2(d) # coarse-level quantizer
index_ivf = faiss.IndexIVFFlat(quantizer, d, nlist)
index_ivf.train(doc_vecs) # required before adding
index_ivf.add(doc_vecs)
index_ivf.nprobe = 10 # search 10 cells; raise for more recall
D, I = index_ivf.search(query, k=2)
print([docs[i] for i in I[0]])
Tune nprobe up to improve recall at the cost of speed. A value of 10 gives ~99% recall on most datasets; 1 gives maximum speed.
Step 3: Save and reload
faiss.write_index(index_ivf, "my_index.faiss")
# --- later ---
index_ivf = faiss.read_index("my_index.faiss")
index_ivf.nprobe = 10 # nprobe isn't saved — reset it
Note: FAISS doesn't store your original text — keep a parallel list or database to map integer indices back to documents (docs[I[0][0]] in the example above).
Go deeper. Pinecone's FAISS: The Missing Manual series covers HNSW (graph-based, production-grade), Product Quantization (compress 97% of memory), and the Index Factory — and has runnable Colab notebooks for each.
Sources: FAISS: The Missing Manual — Pinecone · Nearest Neighbor Indexes — Pinecone · Official FAISS Python tutorials — GitHub · FAISS Python API reference — GoLinuxCloud