vecq vs usearch vs qdrant-edge: one RAM budget, three different answers

Three engines, one 768-dim index: 3.07 GB against 642 MB. The full head-to-head: recall, latency, build time, and the one column nobody else offers.

vecq vs usearch vs qdrant-edge: one RAM budget, three different answers

Your vector engine is a capacity decision

Three engine families now ship for the same job: store embeddings, return the nearest neighbors. usearch made HNSW graphs the default for embedded workloads, and Qdrant just carved its engine into an in-process library. The first question when picking one is not benchmarks. It is what your RAM budget absorbs when the index grows.

The math: a 768-dimension embedding stored as f32 costs 3,072 bytes per vector. One million vectors means 3.07 GB before your application stores a single document or payload column. On a server that is a rounding error. On a phone or a Raspberry Pi it is the whole budget. That gap is where quantization enters, and it is the reason we built vecq, our training-free quantization library.

This post puts three engines on the same questions: how much RAM the index needs, what recall you get back, and what you give up. The numbers are ours where we measured them, and clearly labeled where they are not.

Three engines, three architectures

usearch is an embedded HNSW library from Unum. Sub-millisecond queries and 0.995 recall, paid for with 3,072 bytes per vector at full precision. Building a 2,000-vector index takes 893 ms, and the graph can vary with insertion order and thread count.

qdrant-edge is Qdrant's in-process engine, extracted from the qdrant monorepo and published on crates.io as qdrant-edge v0.8.0 on August 5. Its dependency tree carries 86 normal dependencies including tokio and tonic for gRPC, io-uring, rayon, and two tokenizer libraries. It behaves like a server engine that lives in your process.

vecq takes the opposite trade. No graph, no training pass. It compresses 768-dim embeddings to 642 bytes per vector at the 5-bit default, 4.78x smaller than f32, then searches with a brute-force scan. Where usearch and qdrant-edge minimize work per query, vecq minimizes bytes per vector.

The head-to-head table

Measured on the official vecq benchmark profile: 2,000 real EmbeddingGemma 300M embeddings, 768-dim, aarch64, single-threaded, usearch v2.26.1 as the competitor. Ground truth is exact f32 cosine brute force. Every vecq and usearch number below comes from docs/BENCHMARK.md in the repo, reproducible with cargo run --release -p vecq-bench --bin vs_usearch.

One honesty note before the table: qdrant-edge numbers come from a separate spike on a Modal x86 host over 2,000 synthetic clustered vectors. Different host, different dataset, so read that column as its own experiment that happens to share a table.

enginebytes/vectorbuild (2k vectors)ms/queryrecall@10
usearch f32 (HNSW)3,072893 ms0.230.995
qdrant-edge 0.8.0~3,072 (f32)162 ms (create + upsert)0.371.000
vecq 5-bit (default)64275 ms3.210.979
vecq 4-bit + residual1,028opt-in mode1.760.984

Read it by column. On footprint, vecq is 4.78x smaller at default width and 5.98x at 4-bit. On query latency the graph engines win, and it is not close: 0.23 ms against 3.21 ms at 2,000 vectors, roughly 14x. On build cost, quantization is about 12x faster than HNSW construction, 75 ms against 893 ms.

Recall first, because it decides everything else. usearch returns 0.995. qdrant-edge returned 1.000 in the spike, with a caveat we consider more interesting than the number: at 2,000 vectors, qdrant likely never builds a graph. HNSW implementations index above a size threshold, and below it the engine runs an exact scan. So its 1.000 is partly a property of the scale, not the architecture.

vecq 5-bit returns 0.979. The 4-bit plus residual mode reaches 0.984 at 1,028 bytes per vector and 1.76 ms per query. Nobody adopts a quantized index for exactness. You adopt it to stay under a storage line, and the question is how much recall the line costs.

One more column that never makes it into the table: determinism. vecq is bit-identical across platforms. The same file with the same query returns identical result bits on x86 and ARM, enforced by parity tests on every scoring path. usearch HNSW results can vary with insertion order and threading. If two devices build indexes independently and a sync layer has to reconcile them, that column is the whole decision.

Where each engine belongs

usearch when queries dominate. Read-heavy workloads, existing f32 pipelines, and cases where 0.995 recall at sub-millisecond latency is worth 5x the memory.

qdrant-edge when you want the Qdrant feature set in-process. The pitch is breadth: hybrid dense and sparse search, payload filtering, sync toward a Qdrant server, and a Python stack, with 16,000 crates.io downloads as an early trust signal. The bill for breadth is 86 dependencies in your build, and the release is still labeled beta. Neither fact is a criticism. They are the terms.

vecq when the index lives on the device and every megabyte is negotiated. The positioning is measured, not aspirational: up to roughly 10K vectors, vecq holds recall@10 above 0.93 at default width (0.932 at 10K, 16.5 ms per query single-threaded) and above 0.95 with the residual mode (0.951 at 9.0 ms). The 100K profile is published too, limits included: recall@10 falls to 0.850 at 100K because the true top-10 margins collapse as N grows. A measured boundary beats a marketing curve.

The RAM decision

Back to the opening math, now concrete. The same index, one million 768-dim vectors:

  • f32 (usearch or qdrant-edge, plus graph overhead): 3.07 GB
  • vecq 5-bit: 642 MB
  • vecq 4-bit: 514 MB

Crossing from 3 GB down to about 650 MB is what turns a server-only index into something that runs beside your app. Add zero dependencies in the core path and bit-identical cross-platform results, and that is the trade vecq offers. If your workload does not care about footprint, determinism, or dependency count, the graph engines deserve your next hour.

vecq is Apache-2.0, published on crates.io as vecq-core, and ships as an optional search backend under Uteke. The full width matrix and the 100K profile, caveats included, live in docs/BENCHMARK.md of the repo.