When to use this
You run Qdrant and need a tested way to back it up: before an upgrade, on a schedule or to recover from a bad write. Snapshots are the built-in method. Rebuilding by re-embedding your source documents is the other, and it's often slow and costly. See rebuild vs snapshot to decide between them.
What a snapshot contains
| Type | Scope | Endpoint |
|---|---|---|
| Collection snapshot | One collection, on one node | /collections/{name}/snapshots |
| Shard snapshot | One shard | /collections/{name}/shards/{id}/snapshots |
| Full storage snapshot | All collections on one node (single-node use) | /snapshots |
The most important fact: in a distributed cluster, a collection snapshot only holds what's on the node you called. To back up a whole collection, take a snapshot on every node, or per shard, and keep track of which belongs where.
Step 1: set variables and take a look
export Q=http://qdrant-0:6333
export KEY="$QDRANT_API_KEY"
export C=docs
curl -s -H "api-key: $KEY" "$Q/collections/$C" \
| jq '.result | {status, points_count, segments_count, config: .config.params}'
curl -s -H "api-key: $KEY" "$Q/collections/$C/cluster" \
| jq '.result | {peer_id, shard_count, local_shards, remote_shards}'
Record points_count and the configuration. You'll need them later for verification. status should be green before a backup.
Step 2: take a snapshot
curl -s -X POST -H "api-key: $KEY" \
"$Q/collections/$C/snapshots?wait=true" | jq
Then list what's there:
curl -s -H "api-key: $KEY" "$Q/collections/$C/snapshots" | jq '.result'
The response shows name, size and creation_time. By default, files go in the node's ./snapshots directory, so check that there's enough free disk first. Snapshots can be as large as the data, and they use additional space temporarily while being created.
kubectl exec -n qdrant qdrant-0 -- df -h /qdrant/snapshots
Step 3: copy it off the node
A snapshot on the same disk isn't a backup. Download it:
SNAP=$(curl -s -H "api-key: $KEY" "$Q/collections/$C/snapshots" \
| jq -r '.result | sort_by(.creation_time) | last | .name')
curl -f -H "api-key: $KEY" -o "$SNAP" \
"$Q/collections/$C/snapshots/$SNAP"
sha256sum "$SNAP" > "$SNAP.sha256"
aws s3 cp "$SNAP" "s3://qdrant-backups/$C/$(date +%F)/"
aws s3 cp "$SNAP.sha256" "s3://qdrant-backups/$C/$(date +%F)/"
Then delete the local copy on the node, if you need the space:
curl -s -X DELETE -H "api-key: $KEY" "$Q/collections/$C/snapshots/$SNAP?wait=true"
Qdrant can also write snapshots straight to S3-compatible storage. Set it in the config:
storage:
snapshots_config:
snapshots_storage: s3
s3_config:
bucket: qdrant-backups
region: ap-south-1
access_key: ""
secret_key: ""
Check the exact options for your version. Use a credential from a secret store, not a value in this file.
Step 4: back up a distributed cluster
Loop through every node:
#!/usr/bin/env bash
set -euo pipefail
DATE=$(date +%F)
for NODE in qdrant-0 qdrant-1 qdrant-2; do
URL="http://$NODE.qdrant-headless:6333"
NAME=$(curl -fsS -X POST -H "api-key: $KEY" \
"$URL/collections/$C/snapshots?wait=true" | jq -r '.result.name')
curl -fsS -H "api-key: $KEY" -o "/tmp/$NODE-$NAME" \
"$URL/collections/$C/snapshots/$NAME"
aws s3 cp "/tmp/$NODE-$NAME" "s3://qdrant-backups/$C/$DATE/$NODE/$NAME"
curl -fsS -X DELETE -H "api-key: $KEY" "$URL/collections/$C/snapshots/$NAME?wait=true"
rm -f "/tmp/$NODE-$NAME"
echo "$NODE done: $NAME"
done
Keep the node name in the path, so you can restore the right file to the right place. Also save the output of /collections/$C/cluster from each node beside the files.
Warning
Node snapshots aren't taken at the same moment. Writes that land in between can leave small differences across nodes. For a clean point in time, pause writes during the backup, or plan to replay recent writes from your ingestion pipeline.
Step 5: restore a collection
From a URL or a path the node can read
curl -s -X PUT -H "api-key: $KEY" -H "Content-Type: application/json" \
"$Q/collections/$C/snapshots/recover?wait=true" \
-d '{"location": "https://backups.contoso.com/docs-snapshot.snapshot", "priority": "snapshot"}'
A file:/// location works too, for files on that node's own disk.
By uploading a file
curl -X POST -H "api-key: $KEY" \
"$Q/collections/$C/snapshots/upload?priority=snapshot&wait=true" \
-H "Content-Type: multipart/form-data" \
-F "snapshot=@./docs-snapshot.snapshot"
The priority setting decides which data wins when a replica already exists:
| Priority | Effect | Use when |
|---|---|---|
snapshot | The snapshot's data wins | Restoring old data over current data |
replica | Existing replica data wins | Adding a node to a healthy cluster |
no_sync | No sync with other replicas | Special cases; read the docs first |
Caution
Restoring overwrites the collection's data on that node, and any writes since the snapshot are lost. In a replicated collection, the default priority can make the old snapshot lose to the newer replica data, so nothing appears to change. Or, used wrongly, old data can replace good data. Before you begin, take a new snapshot of the current state, and stop the writers.
Step 6: restore across a whole cluster
- Stop writers, so ingestion can't change data mid-restore.
- Recreate the same topology, including the shard count and replication factor. Compare with what you saved in Step 4.
- Restore each node's file to the matching node, with
priority=snapshot:
for NODE in qdrant-0 qdrant-1 qdrant-2; do
FILE=$(aws s3 ls "s3://qdrant-backups/$C/2026-11-06/$NODE/" | awk '{print $4}')
URL=$(aws s3 presign "s3://qdrant-backups/$C/2026-11-06/$NODE/$FILE" --expires-in 3600)
curl -fsS -X PUT -H "api-key: $KEY" -H "Content-Type: application/json" \
"http://$NODE.qdrant-headless:6333/collections/$C/snapshots/recover?wait=true" \
-d "{\"location\": \"$URL\", \"priority\": \"snapshot\"}"
echo "$NODE restored"
done
- Wait for the collection to return to
green, and for shard transfers to finish:
curl -s -H "api-key: $KEY" "$Q/collections/$C/cluster" \
| jq '.result | {local_shards, remote_shards, shard_transfers}'
A presigned URL is a temporary credential, so keep its expiry short and don't log it. See shards and replicas for how topology works.
Step 7: verify before you reopen
A successful API response only means the restore finished. Check the data too:
curl -s -H "api-key: $KEY" "$Q/collections/$C" \
| jq '.result | {status, points_count, indexed_vectors_count}'
curl -s -X POST -H "api-key: $KEY" -H "Content-Type: application/json" \
"$Q/collections/$C/points/count" -d '{"exact": true}' | jq
| Check | Expected |
|---|---|
| Status | green (yellow may mean that it's still optimizing) |
| Exact point count | Matches your record, allowing for later writes |
| Vector size and distance | Same as before |
| Payload indexes | Present, in payload_schema |
| Known-item search | Returns the expected IDs |
| Retrieval evaluation | Same recall as before |
Run a known-item search with a vector you saved earlier:
curl -s -X POST -H "api-key: $KEY" -H "Content-Type: application/json" \
"$Q/collections/$C/points/query" \
-d '{"query": [0.12, 0.08, 0.33], "limit": 5, "with_payload": false}' | jq
Use a real vector of your collection's dimension there. Finally, re-apply writes made since the snapshot, from your ingestion pipeline. Then reopen traffic.
Schedule and retention
apiVersion: batch/v1
kind: CronJob
metadata:
name: qdrant-backup
namespace: qdrant
spec:
schedule: "0 1 * * *"
concurrencyPolicy: Forbid
jobTemplate:
spec:
backoffLimit: 1
template:
spec:
restartPolicy: Never
containers:
- name: backup
image: registry.contoso.com/qdrant-backup:1.0
command: ["/scripts/backup.sh"]
Set an S3 lifecycle rule to expire old copies, and alert if a backup hasn't landed by its expected time.
Common errors
| Error | Cause | Fix |
|---|---|---|
Timeout from wait=true | Large collection | Use a longer client timeout, and check the snapshot list afterwards |
No space left on device | Snapshot disk is full | Free up space, and move the snapshot path to bigger storage |
| Restore fails on version | Snapshot from a much newer Qdrant | Restore to the same or a compatible version |
| Restore looks to have no effect | replica priority won | Use priority=snapshot, with care |
Node can't fetch location | Network or an expired URL | Upload the file, or generate a new URL |
| Search is slow after restore | Index still optimizing | Wait for green |
Check the release notes for snapshot compatibility before an upgrade, and restore to the same version when you can.
Prevent it next time
- Do a restore test each quarter on a separate cluster, and time it. An untested backup is only a hope.
- Take a snapshot right before each upgrade.
- Keep the source documents and embedding model version, so you can rebuild as a last resort.
- Related: Qdrant production setup, monitoring and vector database HA.