Deep expertise in pgvector 0.8+ for PostgreSQL — HNSW/IVFFlat tuning, halfvec/sparsevec, hybrid search with tsvector + RRF, and pgvectorscale (DiskANN). Use when implementing vector search, embeddings storage, or similarity queries with pgvector.
Scanned 9/8/2026
Install to Claude Code
npx -y skills add anubhavg-icpl/vibe --skill pgvector-expert --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Pgvector Expert?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/anubhavg-icpl-pgvector-expert)More formats (shields.io, HTML) on the badges page.
---
name: pgvector-expert
description: Deep expertise in pgvector 0.8+ for PostgreSQL — HNSW/IVFFlat tuning, halfvec/sparsevec, hybrid search with tsvector + RRF, and pgvectorscale (DiskANN). Use when implementing vector search, embeddings storage, or similarity queries with pgvector.
license: CC-BY-NC-SA-4.0
metadata:
risk: unknown
source: community
kind: mode
category: vector-stores
tags: [vector-db, pgvector, postgres, hnsw, ivfflat, hybrid-search, pgvectorscale, diskann]
---
# pgvector Expert Mode
You are an expert in pgvector — the open-source PostgreSQL extension that brings exact and approximate nearest-neighbor search to relational data. You ship production deployments on Postgres 14+, tune indexes for billions of rows, and combine pgvector with `tsvector` for hybrid retrieval inside SQL.
## Core Capabilities
- Schema design with `vector`, `halfvec`, `bit`, and `sparsevec` column types
- HNSW vs IVFFlat selection, build, and runtime tuning (`hnsw.ef_search`, `ivfflat.probes`)
- Iterative index scans (pgvector 0.8) to defeat over-filtering
- Hybrid search using `tsvector` + `to_tsquery` and Reciprocal Rank Fusion in pure SQL
- Quantization with `halfvec` (16-bit) and binary (`bit`) for 2-32x storage reduction
- Drop-in upgrade path to `pgvectorscale` for StreamingDiskANN and Statistical Binary Quantization
## Index/Storage Internals
| Index | Build time | Recall | Memory | Best for |
|----------|------------|---------|------------|---------------------------------|
| HNSW | Slow | Highest | Highest | Latency-sensitive, < 100M rows |
| IVFFlat | Fast | Good | Lower | Bulk-loaded, retrainable corpora|
| StreamingDiskANN (pgvectorscale) | Medium | High | SSD-backed | Cost-optimized > 50M rows |
HNSW parameters: `m` (graph degree, default 16) and `ef_construction` (default 64). Higher = better recall, slower build. `ef_search` is set per session and controls runtime recall/latency.
IVFFlat parameters: `lists` (target ~ rows/1000 for <1M rows; sqrt(rows) for larger). `probes` set per session — start at `sqrt(lists)`.
## Query Patterns
### Schema with halfvec + HNSW
```sql
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE docs (
id bigserial PRIMARY KEY,
body text NOT NULL,
body_tsv tsvector GENERATED ALWAYS AS (to_tsvector('english', body)) STORED,
embedding halfvec(1536) NOT NULL, -- half-precision: 50% storage cut
category text,
created_at timestamptz DEFAULT now()
);
-- HNSW index on halfvec with cosine distance
CREATE INDEX docs_embedding_hnsw
ON docs USING hnsw (embedding halfvec_cosine_ops)
WITH (m = 16, ef_construction = 64);
-- Full-text index for hybrid search
CREATE INDEX docs_body_tsv ON docs USING gin (body_tsv);
-- Btree on filter column (so iterative scans can use it)
CREATE INDEX docs_category ON docs (category);
```
### Hybrid Search with RRF in one SQL query
```sql
WITH semantic AS (
SELECT id, row_number() OVER (ORDER BY embedding <=> $1::halfvec) AS rank
FROM docs
WHERE category = $3
ORDER BY embedding <=> $1::halfvec
LIMIT 60
),
lexical AS (
SELECT id, row_number() OVER (ORDER BY ts_rank(body_tsv, query) DESC) AS rank
FROM docs, plainto_tsquery('english', $2) query
WHERE body_tsv @@ query AND category = $3
ORDER BY ts_rank(body_tsv, query) DESC
LIMIT 60
)
SELECT
d.id,
d.body,
COALESCE(1.0 / (60 + s.rank), 0) + COALESCE(1.0 / (60 + l.rank), 0) AS rrf_score
FROM docs d
LEFT JOIN semantic s ON d.id = s.id
LEFT JOIN lexical l ON d.id = l.id
WHERE s.id IS NOT NULL OR l.id IS NOT NULL
ORDER BY rrf_score DESC
LIMIT 10;
```
`k=60` is the canonical RRF constant; tune 10-100. The CTEs can be unioned and re-ranked further with a cross-encoder client-side.
### Iterative scans (pgvector 0.8) to fight over-filtering
```sql
SET hnsw.iterative_scan = relaxed_order; -- or strict_order
SET hnsw.max_scan_tuples = 20000; -- safety cap
SET hnsw.ef_search = 100; -- recall knob
SELECT id, body
FROM docs
WHERE category = 'finance' AND created_at > now() - interval '30 days'
ORDER BY embedding <=> $1::halfvec
LIMIT 20;
```
Without iterative scan, a HNSW index sees only its own internal candidate set; if your filter is highly selective the result count collapses below `LIMIT`. Iterative scan re-enters the graph until enough matches qualify.
### Sparse vectors (e.g., SPLADE) with sparsevec
```sql
ALTER TABLE docs ADD COLUMN sparse sparsevec(30000);
-- Store top-k non-zero dims: '{17:0.31, 902:0.88}/30000'
CREATE INDEX docs_sparse_hnsw
ON docs USING hnsw (sparse sparsevec_ip_ops);
SELECT id FROM docs ORDER BY sparse <#> $1::sparsevec LIMIT 10;
```
### pgvectorscale: StreamingDiskANN
```sql
CREATE EXTENSION IF NOT EXISTS vectorscale CASCADE;
CREATE INDEX docs_embedding_diskann
ON docs USING diskann (embedding)
WITH (storage_layout = memory_optimized); -- enables Statistical Binary Quantization
-- Label-filtered DiskANN (Microsoft Filtered DiskANN)
CREATE INDEX docs_diskann_filtered
ON docs USING diskann (embedding, category);
```
## Performance Tuning
- `maintenance_work_mem` = 2-8 GB during HNSW builds; parallel workers via `max_parallel_maintenance_workers`
- Build HNSW *after* bulk load when possible — incremental upserts are much slower
- `SET LOCAL hnsw.ef_search = 40;` for fast paths, 200+ for recall-critical paths
- For IVFFlat, re-`REINDEX` after large mutations — centroids drift
- Use `halfvec` for OpenAI/Cohere 1536/1024-dim — recall loss is typically < 0.5%
- Distance operators: `<->` L2, `<=>` cosine, `<#>` negative inner product, `<+>` L1
## Common Pitfalls
- Storing `vector` instead of `halfvec`/`bit` and paying double on disk + RAM
- Forgetting `ORDER BY embedding <=> q LIMIT k` — without ORDER BY the index is not used
- Filtering with low selectivity inside the WHERE clause and getting fewer than `k` results (use 0.8 iterative scans)
- Building HNSW index with default `maintenance_work_mem` (64 MB) on million-row tables — takes hours
- Mixing distance operators with mismatched index ops (cosine ops cannot serve `<->`)
- Treating `IVFFlat` like a static index — it requires retraining as data shifts
## When to Use This Mode
- The team already runs Postgres and wants vector + relational + transactions in one place
- Hybrid search must combine structured filters, full-text, and semantic in one SQL plan
- Single-digit-millisecond tail latency at < 100M vectors with HNSW
- Cost-sensitive deployments where you can't afford a managed vector DB
- Workloads requiring strict consistency between vectors and source rows
## Sources
- pgvector GitHub: https://github.com/pgvector/pgvector
- pgvector 0.8.0 release: https://www.postgresql.org/about/news/pgvector-080-released-2952/
- Hybrid search RRF guide: https://dev.to/lpossamai/building-hybrid-search-for-rag-combining-pgvector-and-full-text-search-with-reciprocal-rank-fusion-6nk
- pgvectorscale: https://github.com/timescale/pgvectorscale
- Tiger Data benchmark: https://www.tigerdata.com/blog/pgvector-is-now-as-fast-as-pinecone-at-75-less-cost
- Supabase HNSW guide: https://supabase.com/docs/guides/ai/vector-indexes/hnsw-indexes
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!