IVFFlat vs HNSW Indexes
pgvector offers IVFFlat (inverted file with coarse quantization) and HNSW (hierarchical navigable small world) for approximate nearest neighbor search. Choose based on recall targets, RAM budget, and build-time tolerance.
Search across all documentation pages
pgvector offers IVFFlat (inverted file with coarse quantization) and HNSW (hierarchical navigable small world) for approximate nearest neighbor search. Choose based on recall targets, RAM budget, and build-time tolerance.
-- IVFFlat: cluster lists, probe at query time
CREATE INDEX ON documents
USING ivfflat (embedding extensions.vector_cosine_ops)
WITH (lists = 100);
SET ivfflat.probes = 10;
-- HNSW: graph index (pgvector 0.5+, default choice for many workloads)
CREATE INDEX ON documents
USING hnsw (embedding extensions.vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
SET hnsw.ef_search = 40;When to reach for this: Table exceeds ~50k vectors and exact ORDER BY distance LIMIT k misses latency SLO.
-- Benchmark recall vs latency (run in staging with labeled query set)
EXPLAIN (ANALYZE, BUFFERS)
SELECT id, embedding <=> $1 AS dist
FROM documents
ORDER BY embedding <=> $1
LIMIT 10;
-- Compare index scans
DROP INDEX IF EXISTS documents_ivfflat_idx;
CREATE INDEX documents_ivfflat_idx ON documents
USING ivfflat (embedding extensions.vector_cosine_ops) WITH (lists = 200);
DROP INDEX IF EXISTS documents_hnsw_idx;
CREATE INDEX documents_hnsw_idx ON documents
USING hnsw (embedding extensions.vector_cosine_ops)
WITH (m = 16, ef_construction = 128);
-- Measure: p50/p95 latency, recall@10 vs brute force on sample queriesWhat this demonstrates:
lists tuning and ivfflat.probes at query timem, ef_construction at build and hnsw.ef_search at queryEXPLAIN ANALYZE confirms index scan vs seq scanBuild: k-means clusters (lists centroids). Each vector assigned to nearest list.
Query: Search probes nearest lists, then exact distance within those lists.
| Parameter | Effect |
|---|---|
lists | More lists = smaller cells, larger index, slower build |
ivfflat.probes | Higher = better recall, slower queries |
Pros: Lower memory than HNSW for some shapes; mature on older pgvector.
Cons: Recall sensitive to data distribution; needs REINDEX after large data shifts; lists should scale with sqrt(rows) rule of thumb.
-- lists heuristic for N rows: sqrt(N) to N/1000
-- 1M rows: lists between 1000 and 10000 depending on benchmarksBuild: Layered graph connecting neighbors.
| Parameter | Effect |
|---|---|
m | Max edges per node (16 common) |
ef_construction | Build-time candidate list (higher = better graph, slower build) |
hnsw.ef_search | Query-time candidate list (higher = better recall, slower) |
Pros: Strong recall/latency default for pgvector 0.8+; less sensitive to insert order than IVFFlat.
Cons: Higher RAM during build; index larger on disk; vacuum interactions need monitoring at scale.
| Factor | Prefer IVFFlat | Prefer HNSW |
|---|---|---|
| Recall priority | Moderate, tunable with probes | High out of box |
| Build RAM | Tighter budget | Can spare RAM |
| Steady inserts | Batch rebuild IVFFlat periodically | HNSW handles inserts better |
| pgvector version | Legacy constraints | 0.8+ production default |
| Query latency SLO | Flexible | Strict p95 |
-- After bulk embed import
REINDEX INDEX CONCURRENTLY documents_hnsw_idx;
ANALYZE documents;
-- Monitor invalid indexes
SELECT indexrelid::regclass FROM pg_index WHERE NOT indisvalid;REINDEX after import completes.sqrt(n) and sweep probes in benchmark script.hnsw.ef_search until recall@k plateaus on golden set.vector_cosine_ops with <=>.maintenance_work_mem spikes or build off-peak without CONCURRENTLY on empty clone.| Alternative | Use When | Don't Use When |
|---|---|---|
| Exact scan | < 10k rows | Million-row corpus |
| Partitioned HNSW per tenant | Massive multi-tenant | Tiny tenants, ops overhead |
| External ANN service | Proven PG miss at scale | Join-heavy retrieval pipelines |
| IVFFlat now, HNSW later | Memory emergency | You can afford one rebuild |
Stack versions: This page was written for PostgreSQL 18.4 (stable 18, maintenance 17), pgvector 0.8+, PostGIS 3.5+, pgbouncer 1.x, and Patroni 3.x.
Reviewed by Chris St. John·Last updated Jul 18, 2026