What Is Qdrant? β Definition and How It Works
Learn what Qdrant is, how its payload filtering and collections work, and where it fits among vector stores.
Qdrant is a vector database with a REST and gRPC API. Its distinguishing feature is filtering: arbitrary conditions on a point's payload, applied during the vector search rather than after it.
1. The Model
| Concept | Meaning |
|---|---|
| Collection | A named set of points with one vector configuration |
| Point | An id, one or more vectors, and a JSON payload |
| Payload | Arbitrary JSON, filterable and indexable |
| Named vectors | Several vectors per point, e.g. title and body |
| Filter | must / should / must_not conditions on payload |
2. Creating and Loading
from qdrant_client import QdrantClient, models
client = QdrantClient(url="http://localhost:6333")
client.create_collection(
"chunks",
vectors_config=models.VectorParams(size=1536, distance=models.Distance.COSINE),
)
client.upsert("chunks", points=[
models.PointStruct(
id=1,
vector=embedding,
payload={"source_url": "https://example.com/guide",
"heading": "Timeouts",
"lang": "en",
"fetched_at": "2026-08-18"},
),
])
upsert is genuinely an upsert β re-sending the same id replaces the point, which makes reindexing a page idempotent rather than duplicating it.
3. Filtering Is the Point
hits = client.query_points(
"chunks",
query=query_embedding,
limit=10,
query_filter=models.Filter(
must=[models.FieldCondition(key="lang", match=models.MatchValue(value="en"))],
must_not=[models.FieldCondition(key="tier", match=models.MatchValue(value="untrusted"))],
),
).points
Qdrant applies the filter during graph traversal rather than filtering a fixed candidate set afterwards. That matters: post-filtering a top-100 result set by a condition matching 1% of the corpus returns almost nothing, whereas filtering during search keeps returning results until it has ten.
This is the specific weakness of naive ANN-plus-filter designs, and the reason Qdrant is chosen for workloads with selective filters.
4. Payload Indexes
Filtering is only fast if the payload field is indexed:
client.create_payload_index("chunks", field_name="lang",
field_schema=models.PayloadSchemaType.KEYWORD)
client.create_payload_index("chunks", field_name="fetched_at",
field_schema=models.PayloadSchemaType.DATETIME)
An unindexed filter field still works and scans, which on a large collection is slow enough to look like a bug. Index every field you filter on.
5. Useful Features for Collected Data
Named vectors β one point carrying separate title and body embeddings, queried independently. Useful when a heading and its content deserve different treatment.
Sparse vectors β Qdrant supports sparse alongside dense, enabling hybrid lexical-plus-semantic search in one query rather than fusing two systems.
Quantisation β scalar or binary quantisation cuts memory substantially with tunable recall loss, which is what makes large collections affordable.
Snapshots β collection-level backups, so an index built over an expensive embedding run is recoverable without re-embedding.
That last one has real money attached: re-embedding a large corpus costs API spend, so a restorable snapshot is worth setting up before you need it.
6. Compared With the Alternatives
| Option | Best when |
|---|---|
| Qdrant | Selective payload filtering, hybrid search, self-hosted control |
| pgvector | You already run Postgres and want SQL joins |
| FAISS | Single process, static data, no infrastructure |
| Managed services | You want no operations at all |
7. Operational Notes
- Persist the volume. Running in Docker without a mounted volume loses the collection on restart.
- Pick the distance metric at creation. Changing it means recreating the collection.
- Normalise vectors if you use cosine, or rely on Qdrant's cosine handling consistently β do not mix.
- Batch upserts. One point per request is dramatically slower than batches of a few hundred.
- Watch memory. Vectors are held in memory by default; enable on-disk storage or quantisation for large collections.
8. Summary
Qdrant is a vector database with collections of points carrying vectors and arbitrary JSON payloads, queried over REST or gRPC.
Its defining strength is filtering applied during search rather than after, which is what keeps selective filters from returning almost nothing β provided you create payload indexes on every field you filter, batch your upserts, and mount a persistent volume.