pgvector vs Weaviate vs Qdrant: Self-Hosted Vector Database Comparison 2026
TL;DR — pgvector vs Weaviate vs Qdrant: three self-hosted vector databases with distinct philosophies. KalviumLabs: "Four databases, four design philosophies: pgvector is a Postgres extension, Weaviate is hybrid retrieval first-class, Qdrant is OSS-first with Rust performance." DevTo: "Use Qdrant for fastest filtered search and self-hosted Rust. Weaviate for hybrid BM25+vector. pgvector for Postgres simplicity." CallMissed: "Each represents a distinct philosophy — managed serverless, OSS-first with managed tier, hybrid retrieval first-class, or just use Postgres." Layerbase: "Qdrant is the open-source speed leader in Rust, 10-25% faster than Weaviate or Milvus. pgvector by default with no separate provisioning." StochasticSandbox: "Qdrant: payload index + filterable HNSW, adaptive fallback. Weaviate: roaring bitmap with inverted indexes. pgvector: SQL WHERE." Learn more with pgvector tutorial, pgvector vs Pinecone, vector databases, and hybrid search.
KalviumLabs frames the comparison: "Four databases, four different design philosophies: pgvector is a Postgres extension, Weaviate is hybrid retrieval first-class, Qdrant is OSS-first with Rust performance. Our pgvector and Pinecone numbers come from production systems. For Qdrant and Weaviate, we reference published benchmarks."
CallMissed summarizes the philosophies: "Each represents a distinct philosophy — fully managed serverless, OSS-first with a managed tier, hybrid retrieval as a first-class feature, or just use Postgres."
Three-Way Comparison Architecture
Feature Comparison
| Feature | pgvector | Weaviate | Qdrant |
|---|---|---|---|
| Language | C (Postgres extension) | Go | Rust |
| Philosophy | Just use Postgres | Hybrid retrieval first-class | OSS speed leader |
| Index | HNSW, IVFFlat | HNSW + composite | HNSW (custom) |
| Quantization | Binary, halfvec | PQ (1.22+) | Scalar + binary PQ |
| Filtering | SQL WHERE | Roaring bitmap + inverted | Payload index + filterable HNSW |
| Hybrid search | ParadeDB BM25 | Native BM25 + vector | Sparse + dense (RRF/DBSF) |
| Multi-vector | No | No | Yes (named vectors) |
| Sparse vectors | sparsevec | Yes | Yes |
| API | SQL | GraphQL + REST | REST + gRPC |
| Deployment | Postgres extension | Docker / K8s / cloud | Docker / K8s / cloud |
| Distributed | Postgres replication | Sharding | Sharding + Raft |
| ACID | Yes (full Postgres) | No | No |
| SQL JOINs | Yes | No | No |
| Managed cloud | Supabase, Neon, Aurora | Weaviate Cloud | Qdrant Cloud |
| Max scale | ~100M (pgvectorscale) | 100M+ | 1B+ |
| Speed | Good (5-20ms at 1M) | Good | Best (10-25% faster) |
| Filtered search | SQL WHERE | Roaring bitmap | Adaptive in-graph (fastest) |
Decision Matrix
| Use Case | Recommended | Reason |
|---|---|---|
| Already on Postgres, <5M vectors | pgvector | No new infra, SQL JOINs, ACID |
| Need native hybrid BM25+vector | Weaviate | First-class hybrid retrieval |
| Need fastest filtered search | Qdrant | Adaptive in-graph filtering in Rust |
| Need multi-vector (ColBERT/ColPali) | Qdrant | Named vectors + sparse vectors |
| Need SQL JOINs with vectors | pgvector | Vectors alongside relational data |
| Need ACID transactions | pgvector | Full Postgres transactional guarantees |
| K8s self-hosted, 100M-1B vectors | Qdrant | Distributed, sharding + Raft, Rust speed |
| Need GraphQL API | Weaviate | GraphQL + REST API built-in |
| Minimize infrastructure | pgvector | Use existing Postgres, no new service |
| Need sparse + dense hybrid | Qdrant | RRF or DBSF fusion, first-class |
| Need PQ quantization at scale | Weaviate or Qdrant | Both support PQ compression |
| Want Rust performance | Qdrant | 10-25% faster than Weaviate or Milvus |
Implementation
from dataclasses import dataclass
from typing import Optional
from enum import Enum
class SelfHostedVectorDB(Enum):
PGVECTOR = "pgvector"
WEAVIATE = "weaviate"
QDRANT = "qdrant"
@dataclass
class SelfHostedVectorDBComparator:
"""Compare pgvector, Weaviate, and Qdrant for self-hosted RAG."""
def recommend(self, existing_postgres: bool = False,
need_sql_joins: bool = False,
need_acid: bool = False,
need_native_hybrid: bool = False,
need_fastest_filtering: bool = False,
need_multi_vector: bool = False,
need_graphql: bool = False,
vector_count: int = 1_000_000,
prefer_rust: bool = False) -> dict:
"""Recommend self-hosted vector database."""
scores = {SelfHostedVectorDB.PGVECTOR: 0,
SelfHostedVectorDB.WEAVIATE: 0,
SelfHostedVectorDB.QDRANT: 0}
if existing_postgres:
scores[SelfHostedVectorDB.PGVECTOR] += 3
if need_sql_joins:
scores[SelfHostedVectorDB.PGVECTOR] += 3
if need_acid:
scores[SelfHostedVectorDB.PGVECTOR] += 2
if vector_count <= 5_000_000:
scores[SelfHostedVectorDB.PGVECTOR] += 1
if need_native_hybrid:
scores[SelfHostedVectorDB.WEAVIATE] += 3
if need_graphql:
scores[SelfHostedVectorDB.WEAVIATE] += 2
if 100_000_000 <= vector_count <= 500_000_000:
scores[SelfHostedVectorDB.WEAVIATE] += 1
if need_fastest_filtering:
scores[SelfHostedVectorDB.QDRANT] += 3
if need_multi_vector:
scores[SelfHostedVectorDB.QDRANT] += 3
if prefer_rust:
scores[SelfHostedVectorDB.QDRANT] += 2
if vector_count > 500_000_000:
scores[SelfHostedVectorDB.QDRANT] += 2
winner = max(scores, key=scores.get)
reasons = {
SelfHostedVectorDB.PGVECTOR: (
"pgvector: Postgres extension, SQL JOINs, "
"ACID, no new infrastructure"),
SelfHostedVectorDB.WEAVIATE: (
"Weaviate: native hybrid BM25+vector, "
"GraphQL API, roaring bitmap filtering"),
SelfHostedVectorDB.QDRANT: (
"Qdrant: fastest filtered search in Rust, "
"multi-vector, sparse+dense hybrid, "
"scalar+binary PQ"),
}
return {
"recommendation": winner.value,
"reason": reasons[winner],
"scores": {k.value: v for k, v in scores.items()},
}
def get_pgvector_example(self) -> str:
"""pgvector: SQL-based vector search."""
return (
"-- pgvector: vector search with SQL JOIN\n"
"SELECT d.id, d.title, d.content,\n"
" d.embedding <=> '[0.1,...]'::vector AS dist\n"
"FROM documents d\n"
"JOIN departments dep ON d.dept_id = dep.id\n"
"WHERE dep.name = 'engineering'\n"
"ORDER BY d.embedding <=> '[0.1,...]'::vector\n"
"LIMIT 5;"
)
def get_weaviate_example(self) -> str:
"""Weaviate: hybrid search with GraphQL."""
return (
"import weaviate\n"
"\n"
"client = weaviate.connect_to_local()\n"
"\n"
"collection = client.collections.get('Document')\n"
"\n"
"# Hybrid search (BM25 + vector)\n"
"results = collection.query.hybrid(\n"
" query='machine learning architecture',\n"
" alpha=0.5, # 0=keyword, 1=vector\n"
" limit=5,\n"
" filters=Filter.by_property(\n"
" 'category').equal('tech')\n"
")"
)
def get_qdrant_example(self) -> str:
"""Qdrant: filtered search with payload index."""
return (
"from qdrant_client import QdrantClient\n"
"from qdrant_client.models import (\n"
" Filter, FieldCondition, MatchValue)\n"
"\n"
"client = QdrantClient(host='localhost', port=6333)\n"
"\n"
"# Filtered vector search\n"
"results = client.search(\n"
" collection_name='documents',\n"
" query_vector=[0.1, ...],\n"
" query_filter=Filter(\n"
" must=[\n"
" FieldCondition(\n"
" key='category',\n"
" match=MatchValue(value='tech')\n"
" )\n"
" ]\n"
" ),\n"
" limit=5\n"
")"
)
def get_filtering_comparison(self) -> dict:
"""Compare filtering approaches."""
return {
"pgvector": {
"approach": "SQL WHERE clauses",
"mechanism": "Postgres query planner optimizes "
"filter + vector search",
"selective_filters": "May scan more vectors "
"for highly selective filters",
"best_for": "Moderate selectivity, "
"complex relational filters",
},
"weaviate": {
"approach": "Roaring bitmap intersection",
"mechanism": "Inverted indexes on metadata, "
"bitmap intersection for filtering",
"selective_filters": "Good performance with "
"bitmap optimization",
"best_for": "Property-based filtering, "
"hybrid search",
},
"qdrant": {
"approach": "Payload index + filterable HNSW",
"mechanism": "Checks filter during graph "
"traversal, skips non-matching",
"selective_filters": "Adaptive: falls back to "
"brute-force for <1% match",
"best_for": "Fastest filtered search, "
"highly selective filters",
},
}
def get_performance_comparison(self) -> dict:
"""Performance comparison at 1M vectors."""
return {
"query_latency_1M": {
"pgvector_hnsw": "5-20ms at 95%+ recall",
"weaviate_hnsw": "8-25ms",
"qdrant_hnsw": "5-15ms (Rust advantage)",
},
"filtered_search": {
"pgvector": "Depends on Postgres query planner",
"weaviate": "Good with roaring bitmap",
"qdrant": "Fastest with adaptive in-graph filtering",
},
"throughput": {
"pgvector": "Limited by Postgres connections",
"weaviate": "Good, Go concurrency",
"qdrant": "Best, Rust + async I/O",
},
"notes": (
"Qdrant is 10-25% faster than Weaviate or Milvus "
"on common workloads (Layerbase). "
"pgvector matches at 1M scale with HNSW. "
"Performance difference is smaller than "
"embedding API latency in RAG pipelines."
),
}
pgvector vs Weaviate vs Qdrant Checklist
- [ ] pgvector: PostgreSQL extension, C, SQL JOINs, ACID, just use Postgres philosophy
- [ ] Weaviate: Go, hybrid retrieval first-class, GraphQL + REST, roaring bitmap filtering
- [ ] Qdrant: Rust, OSS speed leader, fastest filtered search, multi-vector support
- [ ] Qdrant is 10-25% faster than Weaviate or Milvus on common workloads
- [ ] pgvector with HNSW queries 1M vectors in 5-20ms at 95%+ recall
- [ ] Performance difference is smaller than embedding API latency in RAG pipelines
- [ ] pgvector filtering: SQL WHERE clauses, depends on Postgres query planner
- [ ] Weaviate filtering: roaring bitmap with inverted indexes on metadata properties
- [ ] Qdrant filtering: payload index + filterable HNSW, adaptive fallback for <1% match
- [ ] Qdrant has the fastest filtered search — adaptive in-graph filtering in Rust
- [ ] Weaviate has native BM25 + vector hybrid search as a first-class feature
- [ ] Qdrant has sparse + dense hybrid search with RRF or DBSF fusion
- [ ] pgvector hybrid search requires ParadeDB extension for BM25 inside Postgres
- [ ] For production hybrid search, Weaviate or Qdrant are better choices
- [ ] Qdrant supports multi-vector (ColBERT/ColPali) with named vectors
- [ ] Qdrant supports sparse vectors as first-class
- [ ] pgvector supports sparsevec type
- [ ] Weaviate supports sparse vectors
- [ ] pgvector: HNSW and IVFFlat indexes, binary quantization, halfvec
- [ ] Weaviate: HNSW + composite index, PQ quantization (1.22+)
- [ ] Qdrant: HNSW (custom), scalar + binary PQ quantization
- [ ] pgvector: ACID transactions, point-in-time recovery, standard Postgres backups
- [ ] Weaviate and Qdrant: no ACID transactions
- [ ] pgvector: SQL JOINs combining vector search with relational queries
- [ ] Weaviate and Qdrant: no SQL JOINs — API only
- [ ] pgvector: max scale ~5M (100M with pgvectorscale StreamingDiskANN)
- [ ] Weaviate: max scale 100M+ with distributed sharding
- [ ] Qdrant: max scale 1B+ with sharding + Raft consensus
- [ ] pgvector: deployment as Postgres extension (Supabase, Neon, Aurora)
- [ ] Weaviate: deployment via Docker, K8s, or Weaviate Cloud
- [ ] Qdrant: deployment via Docker, K8s, or Qdrant Cloud
- [ ] pgvector: no new infrastructure if already on Postgres
- [ ] Weaviate and Qdrant: separate service to deploy and manage
- [ ] pgvector: managed by Supabase, Neon, Aurora, Cloud SQL
- [ ] Weaviate: managed by Weaviate Cloud
- [ ] Qdrant: managed by Qdrant Cloud
- [ ] Choose pgvector if already on Postgres and fewer than 5M vectors
- [ ] Choose pgvector if you need SQL JOINs with vector search
- [ ] Choose pgvector if you need ACID transactions for vectors
- [ ] Choose Weaviate if you need native hybrid BM25+vector search
- [ ] Choose Weaviate if you need GraphQL API
- [ ] Choose Qdrant if you need the fastest filtered search
- [ ] Choose Qdrant if you need multi-vector (ColBERT/ColPali) support
- [ ] Choose Qdrant if you want Rust performance (10-25% faster)
- [ ] Choose Qdrant for K8s self-hosted at 100M-1B vectors
- [ ] Choose Qdrant if you need sparse + dense hybrid with RRF/DBSF fusion
- [ ] Four databases, four design philosophies — operational realities matter
- [ ] Read pgvector tutorial for setup
- [ ] Read pgvector vs Pinecone for managed comparison
- [ ] Read vector databases for fundamentals
- [ ] Read hybrid search for BM25 + vector
- [ ] Read what is RAG for architecture
- [ ] Read embeddings for vector fundamentals
- [ ] Test: Qdrant filtered search outperforms at high selectivity
- [ ] Test: Weaviate hybrid search combines BM25 + vector correctly
- [ ] Test: pgvector SQL JOIN combines vector search with relational data
- [ ] Test: recommendation logic selects correct database per use case
- [ ] Document choice, rationale, filtering approach, and scaling strategy
FAQ
How do pgvector, Weaviate, and Qdrant compare for production RAG?
pgvector offers Postgres simplicity with SQL JOINs, Weaviate excels at hybrid BM25+vector search, and Qdrant offers the fastest filtered search in Rust. KalviumLabs: "Four databases, four different design philosophies: pgvector is a Postgres extension, Weaviate is hybrid retrieval first-class, Qdrant is OSS-first with Rust performance. Our pgvector numbers come from production systems. For Qdrant and Weaviate, we reference published benchmarks." DevTo: "Use Qdrant if you need the absolute fastest filtered search, you want to self-host, or you are building in Rust. Their filtering performance is unmatched." CallMissed: "Each represents a distinct philosophy — fully managed serverless, OSS-first with managed tier, hybrid retrieval as first-class feature, or just use Postgres." Layerbase: "Qdrant is the open-source speed leader. Written in Rust, which shows up in the latency numbers. Public benchmarks have Qdrant about 10-25% faster than Weaviate or Milvus on common workloads."
Which has the best filtering performance: pgvector, Weaviate, or Qdrant?
Qdrant has the best filtering performance, using an adaptive approach with payload index and filterable HNSW. DevTo: "Use Qdrant if you need the absolute fastest filtered search. Their filtering performance is unmatched." StochasticSandbox: "Qdrant uses a payload index combined with a filterable HNSW. During graph traversal, it checks filter conditions on each visited node and skips non-matching nodes. When the filter is very selective (<1% match), it falls back to a pre-filtered set with brute-force search. This adaptive approach handles edge cases well. Weaviate uses a roaring bitmap intersection approach with inverted indexes on metadata properties." KalviumLabs: "pgvector filtering uses SQL WHERE clauses — simple but may not be as optimized for highly selective filters at scale." Ranking: (1) Qdrant — adaptive in-graph filtering with payload index. (2) Weaviate — roaring bitmap with inverted indexes. (3) pgvector — SQL WHERE, depends on Postgres query planner.
Which is best for hybrid search: pgvector, Weaviate, or Qdrant?
Weaviate and Qdrant both offer first-class hybrid search, while pgvector requires ParadeDB for BM25. CallMissed: "Weaviate represents hybrid retrieval as a first-class feature." StochasticSandbox: "Weaviate uses a roaring bitmap intersection approach. It maintains inverted indexes on metadata properties, computes a bitmap. Qdrant uses sparse + dense vector hybrid search with RRF or DBSF fusion." KalviumLabs: "pgvector hybrid search requires ParadeDB for BM25 inside Postgres. Weaviate and Qdrant handle hybrid natively." Hybrid search comparison: (1) Weaviate — native BM25 + vector hybrid with fused scoring. (2) Qdrant — sparse + dense hybrid with RRF or DBSF fusion. (3) pgvector — requires ParadeDB extension for BM25, or manual fusion in SQL. For production hybrid search, Weaviate or Qdrant are better choices.
When should you choose Qdrant over pgvector and Weaviate?
Choose Qdrant when you need the fastest filtered search, want self-hosted with Rust performance, or need multi-vector (ColBERT) support. DevTo: "Use Qdrant if you need the absolute fastest filtered search, you want to self-host, or you are building in Rust." Layerbase: "Qdrant is the open-source speed leader. Written in Rust. 10-25% faster than Weaviate or Milvus on common workloads." StochasticSandbox: "Qdrant: named vectors + sparse vectors. Multi-vector (ColBERT-style late interaction) is first class. Scalar + binary PQ. Payload index + ranged filtering. Distributed cluster (sharding + Raft)." Choose Qdrant when: (1) You need the fastest filtered search performance. (2) You want self-hosted with Rust speed. (3) You need multi-vector (ColBERT/ColPali) support. (4) You need sparse + dense hybrid search. (5) You want scalar + binary quantization. (6) You need distributed clustering with sharding.
When should you choose pgvector over Weaviate and Qdrant?
Choose pgvector when you already use PostgreSQL, need SQL JOINs with vector search, want ACID transactions, or want to minimize infrastructure. KalviumLabs: "pgvector is a Postgres extension — vector search alongside relational data. Our pgvector numbers come from production systems." CallMissed: "pgvector represents the just use Postgres philosophy." Layerbase: "Layerbase Cloud hosts pgvector as part of the regular Postgres engine, so you get pgvector by default with no separate provisioning." Choose pgvector when: (1) You already use PostgreSQL — no new infrastructure. (2) You need SQL JOINs combining vector search with relational queries. (3) You need ACID transactions for vectors. (4) You have fewer than 5M vectors (or 100M with pgvectorscale). (5) You want to minimize infrastructure and operational burden. (6) You want point-in-time recovery and standard Postgres backups. (7) You want to avoid managing a separate vector database.
Want a self-hosted AI company brain that does all of this out of the box?
Book a demo →