Qdrant is an open-source vector database written in Rust. It stores embeddings with JSON payloads, and runs fast similarity search with rich filtering. It’s a popular choice for RAG (retrieval-augmented generation), semantic search and recommendations. Self-hosting it on a VPS keeps your data private, with no per-vector pricing.
Requirements
- Docker. See installing Docker on Ubuntu.
- RAM: plan for your vectors plus overhead. One million 768-dimension float vectors take about 3 GB in memory. Qdrant can keep vectors on disk (
on_disk) and use quantization to cut memory use substantially. - SSD storage. See how much RAM a VPS needs.
Docker Compose
# /opt/qdrant/compose.yaml
services:
qdrant:
image: qdrant/qdrant:latest
restart: unless-stopped
ports:
- "127.0.0.1:6333:6333" # REST API + web dashboard
- "127.0.0.1:6334:6334" # gRPC
environment:
QDRANT__SERVICE__API_KEY: ${QDRANT_API_KEY}
volumes:
- ./storage:/qdrant/storage
cd /opt/qdrant
echo "QDRANT_API_KEY=$(openssl rand -hex 32)" > .env
docker compose up -d
curl -H "api-key: $(grep -oP '(?<==).*' .env)" http://127.0.0.1:6333/
Ports are bound to localhost. Applications on the same server connect directly, and remote applications should go through a reverse proxy with HTTPS (or a private network), always with the API key. Pin a specific version tag in production instead of latest. See Docker Compose in production.
Expose it securely (optional)
server {
server_name qdrant.example.com;
client_max_body_size 64m;
location / {
proxy_pass http://127.0.0.1:6333;
proxy_set_header Host $host;
}
}
Add HTTPS with Certbot, and restrict access by IP if only your app servers need it. The web dashboard is at /dashboard. See reverse proxy on a VPS and Let’s Encrypt with Certbot on Nginx.
Create a collection
The vector size must match your embedding model. Choose the distance the model was trained for (usually Cosine for text):
curl -X PUT http://127.0.0.1:6333/collections/docs \
-H "api-key: $QDRANT_API_KEY" -H "Content-Type: application/json" \
-d '{"vectors": {"size": 768, "distance": "Cosine"}}'
Distances: Cosine, Dot, Euclid, Manhattan.
Insert points
A point has an ID, a vector, and an optional JSON payload (metadata used for filtering and returned with results):
curl -X PUT "http://127.0.0.1:6333/collections/docs/points?wait=true" \
-H "api-key: $QDRANT_API_KEY" -H "Content-Type: application/json" \
-d '{"points": [
{"id": 1, "vector": [0.01, 0.02, …], "payload": {"source": "nginx.md", "lang": "en"}},
{"id": 2, "vector": [0.03, -0.01, …], "payload": {"source": "docker.md", "lang": "en"}}
]}'
Search with the Python client
from qdrant_client import QdrantClient, models
client = QdrantClient(url="http://127.0.0.1:6333", api_key=QDRANT_API_KEY)
hits = client.query_points(
collection_name="docs",
query=embed("How do I enable HTTPS?"), # your embedding function
query_filter=models.Filter(must=[
models.FieldCondition(key="lang", match=models.MatchValue(value="en"))
]),
limit=5,
with_payload=True,
).points
for h in hits:
print(h.score, h.payload["source"])
(pip install qdrant-client.) For fields you filter on often, create a payload index, so filtered searches stay fast:
client.create_payload_index("docs", field_name="lang", field_schema="keyword")
Save memory
- Quantization (scalar int8, binary, or product) shrinks vectors in RAM, with little recall loss. Original vectors can stay on disk for rescoring.
on_disk: truefor vectors, and payload stored on disk, for large collections on smaller servers.- Tune the HNSW index (
m,ef_construct) only if defaults don’t meet your recall or latency targets.
Backups
Qdrant has a built-in API to create a consistent copy of a collection (POST /collections/docs/snapshots), saved under the storage directory. Copy those files off the server regularly, or back up the storage volume with the container stopped. See Docker volume backups and restic backups.
Updates
docker compose pull && docker compose up -d
Read the release notes before major version jumps: Qdrant supports upgrading one minor version at a time for storage compatibility.
Qdrant vs pgvector
| Qdrant | pgvector | |
|---|---|---|
| Setup | Separate service | Extension in PostgreSQL |
| Filtering | Rich payload filters, payload indexes | SQL WHERE |
| Memory tools | Quantization, on-disk vectors | halfvec, standard PG tuning |
| Joins and transactions | No | Yes |
| Best for | Dedicated, large or filter-heavy vector search | Apps already on PostgreSQL |
See pgvector and vector databases.
Quick reference
| Task | How |
|---|---|
| Run | qdrant/qdrant image, ports 6333/6334 |
| Secure | QDRANT__SERVICE__API_KEY, localhost bind, HTTPS proxy |
| Collection | PUT /collections/{name} with size + distance |
| Insert | PUT /collections/{name}/points |
| Search | client.query_points(…) |
| Fast filters | Payload indexes |
| Dashboard | /dashboard |
Related: VPS for AI workloads.