Your RAG stack got lean. Your vector layer didn't. Meet vecq.

A 515-point HN thread says RAG needs less machinery. vecq is our answer for the layer it skipped: 4.8x smaller vectors, zero dependencies, one deterministic file.

Your RAG stack got lean. Your vector layer didn't. Meet vecq.

vecq compresses vector embeddings about 4.8x with a recall cost you can count on one hand, and it does it with zero dependencies in a single deterministic file. It ships as a Rust crate, v0.3.0, live on crates.io today. We built it because we kept paying for a full vector database in places where one file was the honest right answer.

Last week an essay called "RAG Is Simpler Than You Think" hit 515 points on Hacker News with 216 comments. Its argument is our argument, so let's start there, and then go one layer deeper than the essay went.

The 515-point argument

Rafael Pierre's essay at Lighthouse says most people over-engineer retrieval. Users just want the document that says "how to reset my password," and the essay's first recipe is the oldest tool in the box: BM25 full-text search. No embeddings, no chunking strategy, no evaluation harness, no model deprecation risk. Before you reach for vectors, it argues, check five decision factors: data freshness, corpus churn, query patterns, query volume, and team ML experience. Keyword-heavy queries on a stable corpus at modest scale? Full-text search wins, and you were about to build a pipeline.

Fair warning if you click through: the essay sits behind a subscribe wall after the first recipe. The decision factors above and Recipe 1 are free, and the 216-comment HN thread (linked at the end) is where the community stress-tested the rest in public, which is arguably a better read anyway.

We agree with the thesis. And we think it stops one component short.

Even a lean stack stores vectors raw

Say your decision factors land where the essay says embeddings earn their keep: conversational queries, semantic intent, a corpus that changes too fast for keyword recall to cover. Fine. Now look at what that choice costs you at the storage layer, because almost nobody does.

A 768-dimension f32 embedding is 3,072 bytes. One million vectors is about 3GB before you add a single metadata field. On a server you shrug and provision. On a phone, an edge device, a CLI tool, or a laptop app, 3GB of vectors plus a C++ HNSW library behind FFI bindings plus (in the default path) a running database process is not lean by any reading of the word.

The lean-RAG critique demolished over-built retrieval pipelines. The vector store, the component everyone copies from a 2021 tutorial, usually escaped it. That's the layer vecq rebuilds.

What vecq does

vecq is training-free vector quantization and search in a pure Rust crate. The pipeline, in three steps: a random diagonal Hadamard rotation spreads each vector's energy so its coordinates behave like samples from a fixed normal distribution (the rotation seed lives in the file header, so results are identical everywhere). Precomputed Lloyd-Max quantizer constants, embedded in the binary, map those coordinates to compact codes. No training pass, nothing learned from your data, nothing to drift. Scoring is asymmetric: queries stay f32, only the stored side is quantized, with a per-vector scale correction that keeps the score an honest cosine estimate.

The default 5-bit width lands at 642 bytes per vector with recall@10 of 0.979 against exact cosine ground truth on real embeddings. Everything is one file: write it, copy it, ship it inside your binary, mmap it for a zero-copy read that parses in microseconds. Results are bit-identical across platforms, and the repo's test suite enforces that with bitwise parity checks between SIMD and scalar paths.

The numbers, from our published benchmark (real EmbeddingGemma embeddings, 768-dim, aarch64 release build, 2,000 vectors):

mode bytes/vector recall@10 ms/query
5-bit (default) 642 0.979 3.21
4-bit 514 0.958 0.89
6-bit 770 0.980 3.24
4-bit + residual 1,028 0.984 1.76

Full methodology lives in docs/BENCHMARK.md and the benchmark harness is in the repo, so run it yourself. One honesty note the README also carries: those latencies come from our aarch64 host. The ordering replicates everywhere; absolute times vary by machine.

For scale of the speed difference, building an index over 2,000 vectors takes vecq 75ms. The same job on a popular HNSW library (usearch, f32) takes 893ms and stores 3,072 bytes per vector to vecq's 642. Different tools, different tradeoffs, but the direction is consistent: vecq trades a sliver of last-mile recall for a fraction of the size, zero dependencies, and build times you can watch.

When you shouldn't use vecq

The README says it in the same words we mean: vecq is deliberately small and simple, not a Qdrant replacement. If you need exact search, payload filtering, or server-scale throughput, use a real vector database. vecq is for the place where the vectors live on the device and size, cold-start, and determinism matter more than the last 1.6% of recall.

Publishing the "don't use this" list next to the benchmark is the point. A compression tool that refuses to state its limits is selling you the 3GB problem all over again.

Where it already runs

vecq is the optional search backend in uteke, our memory engine for AI agents (we published a longer piece on that side of the stack). Same philosophy end to end: your data in formats you own, on hardware you control, with nothing phoning home.

Try it

cargo add vecq-core
use vecq_core::VecqIndex;

let mut index = VecqIndex::new(768, 42 /* seed */);
for v in &vectors { index.add(v); }
let hits: Vec<(usize, f32)> = index.search(&query, 10);

// One deterministic file, portable across platforms.
let bytes = index.to_bytes();

Crate: crates.io/crates/vecq-core. Repository and full benchmark: github.com/codecoradev/vecq.

A lean stack in 2026 can be small all the way down: full-text search where keywords work, embeddings where meaning pays for itself, and one compressed file where the vectors live. The third part is vecq.