This Qdrant cheat sheet is the one-page reference we reach for when running the vector database in real workloads. It covers the commands, REST and gRPC API calls, filter shapes, snapshots, cluster operations, and the configuration env var pattern in one scannable layout. Pin it next to your terminal. For the LLM side of a RAG stack, our Ollama commands cheat sheet is the companion reference.
Every command below was tested against Qdrant v1.18.x. Where you see ${QDRANT_VERSION} in a script, detect the latest with curl -s https://api.github.com/repos/qdrant/qdrant/releases/latest | jq -r .tag_name. For the full series, start with our Qdrant vector database guide. The official reference lives in the Qdrant documentation.
Ports, defaults, and key URLs
| Port / Path | Purpose |
|---|---|
6333 | REST API and Web UI |
6334 | gRPC API |
6335 | P2P / raft consensus (cluster only) |
/dashboard | Built in Web UI |
/healthz | Liveness check |
/readyz | Readiness check |
/metrics | Prometheus / OpenMetrics |
/sys_metrics | System level metrics (host CPU, RAM, disk) |
/cluster | Cluster status |
/collections | Collection list |
/qdrant/storage | Default storage path inside the container |
Run Qdrant with Docker
The fastest way to a working Qdrant. Persistent storage, both ports exposed, container restarts itself.
docker run -d --name qdrant \
-p 6333:6333 -p 6334:6334 \
-v "$(pwd)/qdrant_storage:/qdrant/storage:z" \
--restart unless-stopped \
qdrant/qdrant
With an API key set via env var (recommended for anything reachable beyond localhost):
docker run -d --name qdrant \
-p 6333:6333 -p 6334:6334 \
-v "$(pwd)/qdrant_storage:/qdrant/storage:z" \
-e QDRANT__SERVICE__API_KEY="$(openssl rand -base64 32)" \
--restart unless-stopped \
qdrant/qdrant
GPU enabled image (Qdrant 1.13+, used by the indexing path):
docker run -d --name qdrant \
--gpus all \
-p 6333:6333 -p 6334:6334 \
-v "$(pwd)/qdrant_storage:/qdrant/storage:z" \
qdrant/qdrant:${QDRANT_VERSION}-gpu-nvidia
Docker Compose snippet
A reusable Compose file with persistent storage, an API key from env, and a memory limit for production:
services:
qdrant:
image: qdrant/qdrant:${QDRANT_VERSION} # https://github.com/qdrant/qdrant/releases
container_name: qdrant
restart: unless-stopped
ports:
- "6333:6333"
- "6334:6334"
volumes:
- ./qdrant_storage:/qdrant/storage:z
- ./qdrant_snapshots:/qdrant/snapshots:z
environment:
QDRANT__SERVICE__API_KEY: ${QDRANT_API_KEY}
deploy:
resources:
limits:
memory: 4G
Native install one-liners
| OS | Install |
|---|---|
| Ubuntu / Debian | wget https://github.com/qdrant/qdrant/releases/download/${QDRANT_VERSION}/qdrant_${QDRANT_VERSION#v}_amd64.deb && sudo apt install ./qdrant_*_amd64.deb |
| Rocky / RHEL | Use the Docker or Podman path. Native RPM is not officially published; build from source with cargo if you really need it. |
| Build from source | cargo install --git https://github.com/qdrant/qdrant --tag ${QDRANT_VERSION} (requires Rust toolchain and protoc) |
systemd service for a native install
Drop this unit file at /etc/qdrant/qdrant.service for a native (non-Docker) install:
# /etc/systemd/system/qdrant.service
[Unit]
Description=Qdrant Vector Database
After=network.target
[Service]
Type=simple
User=qdrant
Group=qdrant
ExecStart=/usr/bin/qdrant --config-path /etc/qdrant/config.yaml
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
Create the user, the storage directories, and enable the unit:
sudo useradd -r -s /sbin/nologin qdrant
sudo mkdir -p /var/lib/qdrant/storage /etc/qdrant
sudo chown -R qdrant:qdrant /var/lib/qdrant
sudo systemctl daemon-reload
sudo systemctl enable --now qdrant
sudo systemctl status qdrant
Health and readiness
Three endpoints cover liveness, readiness, and version reporting:
# Liveness
curl -s http://localhost:6333/healthz
# Readiness (returns 200 only when collections are loaded)
curl -s http://localhost:6333/readyz
# Telemetry / version
curl -s http://localhost:6333/telemetry | jq '.app.version'
Collections: create, list, delete
Collections are the top level container. Create, list, inspect, and delete with these calls:
# Create a collection (768-dim, cosine distance)
curl -X PUT http://localhost:6333/collections/articles \
-H "api-key: $QDRANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"vectors": {
"size": 768,
"distance": "Cosine"
}
}'
# List
curl -s http://localhost:6333/collections -H "api-key: $QDRANT_API_KEY"
# Get config and stats
curl -s http://localhost:6333/collections/articles -H "api-key: $QDRANT_API_KEY"
# Delete
curl -X DELETE http://localhost:6333/collections/articles -H "api-key: $QDRANT_API_KEY"
Collection with named vectors (dense + sparse for hybrid search):
curl -X PUT http://localhost:6333/collections/articles \
-H "api-key: $QDRANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"vectors": {
"dense": {"size": 768, "distance": "Cosine"}
},
"sparse_vectors": {
"bm25": {}
}
}'
Points: upsert, get, delete, scroll
Upserts, deletes, scroll, and count all live under the collection's points path:
# Upsert with payload
curl -X PUT http://localhost:6333/collections/articles/points \
-H "api-key: $QDRANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"points": [
{
"id": 1,
"vector": [0.1, 0.2, 0.3, "..."],
"payload": {"title": "Qdrant Guide", "tags": ["ai", "vector"]}
}
]
}'
# Get by ID
curl -s http://localhost:6333/collections/articles/points/1 -H "api-key: $QDRANT_API_KEY"
# Delete by ID
curl -X POST http://localhost:6333/collections/articles/points/delete \
-H "api-key: $QDRANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"points": [1, 2, 3]}'
# Scroll (paginate through all points)
curl -X POST http://localhost:6333/collections/articles/points/scroll \
-H "api-key: $QDRANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"limit": 100, "with_payload": true, "with_vector": false}'
# Count
curl -X POST http://localhost:6333/collections/articles/points/count \
-H "api-key: $QDRANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"exact": true}'
Search and the modern query API
The legacy /search endpoint still works, but new code should use /query which adds prefetch, hybrid retrieval, and rescoring:
# Basic search
curl -X POST http://localhost:6333/collections/articles/points/search \
-H "api-key: $QDRANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"vector": [0.1, 0.2, 0.3, "..."],
"limit": 10,
"with_payload": true
}'
# Modern query_points (v1.10+) with prefetch + filter
curl -X POST http://localhost:6333/collections/articles/points/query \
-H "api-key: $QDRANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": [0.1, 0.2, 0.3, "..."],
"limit": 10,
"filter": {
"must": [{"key": "tags", "match": {"value": "ai"}}]
}
}'
# Recommend (positives and negatives)
curl -X POST http://localhost:6333/collections/articles/points/recommend \
-H "api-key: $QDRANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"positive": [1, 5],
"negative": [99],
"limit": 10
}'
Filter syntax cheat card
| Clause | Example |
|---|---|
match | {"key":"category","match":{"value":"books"}} |
match any | {"key":"tag","match":{"any":["ai","ml"]}} |
range | {"key":"price","range":{"gte":10,"lt":100}} |
geo_bounding_box | {"key":"loc","geo_bounding_box":{"top_left":{...},"bottom_right":{...}}} |
geo_radius | {"key":"loc","geo_radius":{"center":{...},"radius":5000}} |
full text | {"key":"body","match":{"text":"vector search"}} |
is_null | {"is_null":{"key":"deleted_at"}} |
nested | {"key":"meta.tags[]","match":{"value":"ai"}} |
Compose with must, should, and must_not. Always pair high cardinality keyword fields with a payload index for fast filtered search.
# Create a payload index (one-time, per field)
curl -X PUT http://localhost:6333/collections/articles/index \
-H "api-key: $QDRANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"field_name": "tags", "field_schema": "keyword"}'
Snapshots: create, list, restore
Snapshots are the simplest backup path. The same endpoints handle create, list, download, and restore:
# Create a collection snapshot
curl -X POST http://localhost:6333/collections/articles/snapshots \
-H "api-key: $QDRANT_API_KEY"
# List
curl -s http://localhost:6333/collections/articles/snapshots -H "api-key: $QDRANT_API_KEY"
# Download
curl -OJ http://localhost:6333/collections/articles/snapshots/<snapshot-name> \
-H "api-key: $QDRANT_API_KEY"
# Restore from URL
curl -X PUT http://localhost:6333/collections/articles/snapshots/recover \
-H "api-key: $QDRANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"location": "http://backups.example.com/articles.snapshot"}'
# Restore from upload (multipart)
curl -X POST http://localhost:6333/collections/articles/snapshots/upload \
-H "api-key: $QDRANT_API_KEY" \
-F "[email protected]"
# Full storage snapshot (single node only)
curl -X POST http://localhost:6333/snapshots -H "api-key: $QDRANT_API_KEY"
S3 snapshot backend (since v1.10), configured in config.yaml:
storage:
snapshots_config:
snapshots_storage: s3
s3_config:
bucket: my-qdrant-snapshots
region: eu-central-1
access_key: AKIA...
secret_key: ...
endpoint_url: https://s3.eu-central-1.amazonaws.com
Cluster operations
Cluster mode adds raft consensus, sharding, and replication. Enable it in config.yaml:
# Enable cluster mode in config.yaml
cluster:
enabled: true
p2p:
port: 6335
consensus:
tick_period_ms: 100
Bootstrap the first node, then join the rest with the --bootstrap flag pointing at any existing peer:
# Bootstrap node 1 (first in the cluster)
qdrant --config-path /etc/qdrant/config.yaml --uri http://node1:6335
# Join nodes 2 and 3
qdrant --config-path /etc/qdrant/config.yaml \
--bootstrap http://node1:6335 \
--uri http://node2:6335
# Cluster status
curl -s http://localhost:6333/cluster -H "api-key: $QDRANT_API_KEY"
# Create collection with sharding and replication
curl -X PUT http://localhost:6333/collections/articles \
-H "api-key: $QDRANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"vectors": {"size": 768, "distance": "Cosine"},
"shard_number": 6,
"replication_factor": 2,
"write_consistency_factor": 1
}'
# Move a shard between peers
curl -X POST http://localhost:6333/collections/articles/cluster \
-H "api-key: $QDRANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"move_shard": {
"shard_id": 0,
"from_peer_id": 1,
"to_peer_id": 3
}
}'
Helm one-liners
The official Helm chart wraps a StatefulSet plus a PVC per pod. Add the repo and install with the right flags for your topology:
helm repo add qdrant https://qdrant.github.io/qdrant-helm
helm repo update
# Single node
helm install qdrant qdrant/qdrant \
--namespace qdrant --create-namespace \
--set apiKey=$(openssl rand -base64 32)
# 3 node cluster with persistence
helm install qdrant qdrant/qdrant \
--namespace qdrant --create-namespace \
--set replicaCount=3 \
--set config.cluster.enabled=true \
--set persistence.size=50Gi \
--set apiKey=$(openssl rand -base64 32)
# Upgrade
helm upgrade qdrant qdrant/qdrant -n qdrant -f values.yaml
Python client one-page
The qdrant-client Python package mirrors the REST API one-to-one. A working starter:
from qdrant_client import QdrantClient
from qdrant_client.models import (
Distance, VectorParams, PointStruct,
Filter, FieldCondition, MatchValue, Range,
)
client = QdrantClient(url="http://localhost:6333", api_key="...")
# Create
client.create_collection(
collection_name="articles",
vectors_config=VectorParams(size=768, distance=Distance.COSINE),
)
# Upsert
client.upsert(
collection_name="articles",
points=[
PointStruct(id=1, vector=[0.1] * 768, payload={"title": "Qdrant Guide"}),
],
)
# Search with filter
hits = client.query_points(
collection_name="articles",
query=[0.1] * 768,
query_filter=Filter(
must=[FieldCondition(key="title", match=MatchValue(value="Qdrant Guide"))]
),
limit=10,
with_payload=True,
).points
# Create payload index
client.create_payload_index(
collection_name="articles",
field_name="title",
field_schema="keyword",
)
# Snapshot
client.create_snapshot(collection_name="articles")
Configuration env var pattern
Every key in config.yaml can be overridden by an environment variable using QDRANT__SECTION__KEY. Two underscores separate levels.
| Env var | Effect |
|---|---|
QDRANT__SERVICE__API_KEY | Static API key for all requests |
QDRANT__SERVICE__JWT_RBAC | Enable JWT based RBAC (also needs API key) |
QDRANT__SERVICE__HTTP_PORT | REST port (default 6333) |
QDRANT__SERVICE__GRPC_PORT | gRPC port (default 6334) |
QDRANT__SERVICE__ENABLE_TLS | Built in TLS (with tls.cert + tls.key) |
QDRANT__STORAGE__STORAGE_PATH | Storage root (default ./storage) |
QDRANT__STORAGE__SNAPSHOTS_PATH | Snapshots root (default ./snapshots) |
QDRANT__LOG_LEVEL | debug, info, warn, error |
QDRANT__CLUSTER__ENABLED | Turn on cluster mode |
QDRANT__TELEMETRY_DISABLED | Disable anonymous telemetry |
Web UI URLs
| URL | What it shows |
|---|---|
/dashboard | Main UI |
/dashboard#/welcome | First time welcome page |
/dashboard#/collections | Collections list |
/dashboard#/console | Browser REST runner |
/dashboard#/tutorial | Interactive tutorial |
/dashboard#/datasets | Bundled sample datasets |
Common gotchas
- NFS or object storage as the storage backend. Not supported. Qdrant needs block storage with POSIX semantics. Use a PVC backed by a CSI driver that gives you a block volume.
- Forgetting to set the API key before turning on JWT. The API key is the HMAC secret used to sign and verify JWTs. Set
QDRANT__SERVICE__API_KEYfirst, then enablejwt_rbac. - Filtered search without a payload index. The search still works, but it linear scans the filter side. Always create a payload index for high cardinality keyword fields.
- Binary quantization without rescoring. Default behaviour is good, but if you turned rescoring off, expect a recall drop of 5 to 10 percent. Turn it back on or accept the trade.
- Restoring an S3 snapshot directly. Qdrant cannot pull from S3 on restore. Download to a local file, then call the
/snapshots/uploadendpoint. - Cluster of size 2. Raft needs more than half the nodes alive to make progress, so a 2 node cluster cannot tolerate a single failure. Run 1, 3, or 5.
- Default Docker run is open. No auth and no TLS. Fine on a laptop, never on a public host. See our secure Qdrant with API key, TLS, and Nginx article in this series.
Next steps
If you want the full context behind these commands, the pillar Qdrant vector database guide ties everything in this series together. Looking for the equivalent commands for a Postgres-based vector store, our install pgvector walkthrough is the parallel reference.