Vector database standards (the engine as infrastructure)
Criteria verified as of August 2026. Re-verify on the web before committing to anything (§8).
1. Scope and triggers
Applies when you have to deploy, operate, size, back up, scale, secure or pay for a vector
search engine: the decision of whether a dedicated engine is needed at all, the
recall/latency/memory trade-off as an explicit decision, the RAM cost and build time of each
index family, pre-/post-filtering, index persistence and backup, rebuilding, deletion and graph
degradation, replicas and partitioning, multi-tenancy, and the uses of vector similarity that are
not RAG.
Triggers: "do I need a vector database?", "it doesn't fit in memory", "how much RAM does the index
need", "binary/scalar/product quantisation", "compress vectors", "collection snapshot",
"restore an index", "how long does a rebuild take", "cold start", "the engine takes ages to come
up", "replication factor", "collection sharding", "deletion and compaction",
"tombstones", "recall dropped when I added a filter", "the filter returns fewer results than I
ask for", "isolation by collection or by filter", "one tenant per collection", "endpoint with no
authentication", service.api_key, AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED,
authorizationEnabled, ports 6333/6334, 19530, 8080, 8000, "embedding inversion",
"deduplication", "record linkage", "image search", "anomaly detection", "clustering",
"similarity-based recommendation".
Domain thesis: a vector engine is a database that lives in RAM and answers with
approximations. The two halves of that sentence decide everything else: memory is the dominant
resource and the real cost, and recall is not a fact, it is a parameter you have chosen —
consciously or unconsciously.
Arbitration rule with rag-standards (read it before writing anything in this domain): if the
question changes what is retrieved, it belongs to rag-standards; if it changes who operates,
pays for, backs up or restores the engine, it belongs here. Operational corollary: raising
ef_search to improve the recall of a RAG belongs to rag-standards; the node that runs out of RAM
building that index, or the restore that takes six hours, belongs here.
Not applicable:
rag-standards — the critical boundary. It is the retrieval pattern for feeding an
LLM: chunking, choice and lifecycle of the embedding model and its reindexing cost,
choosing between pgvector and a dedicated engine from the perspective of retrieval quality,
HNSW and IVFFlat tuning parameters (m, ef_construction, ef_search, lists,
probes), hybrid dense + BM25 retrieval with RRF fusion, cross-encoder reranking,
metadata filtering as a retrieval technique, recall@k/MRR/nDCG metrics, and per-document
access control in retrieval. None of that is repeated here: when this skill
needs those concepts, it links to them. Here, the engine as a piece of infrastructure and the
non-RAG uses.
data-platform-standards — parent skill: the PostgreSQL engine (modelling, migrations, replicas,
PITR, tuning, RLS, JSONB, full-text) and the guiding principle "one store per need, not per fashion",
which this skill inherits whole. Three-way arbitration for pgvector: the extension and its index
parameters belong to rag-standards; the PostgreSQL that hosts it, its backup, its HA and its patching
belong to data-platform-standards; the criteria for when pgvector stops being enough and what it
costs to operate the dedicated piece that replaces it belong here (§2.2).
search-engines-standards — text engines (Elasticsearch/OpenSearch, Meilisearch, Typesense,
Vespa, Solr), inverted index modelling, BM25 relevance, index lifecycle and cluster
operation. Several of them also do vector search: if the engine is already deployed
for its lexical capability, the criteria for operating it are theirs; if it is deployed for the
vectors, they belong here. Hybrid search crosses all three skills: the fusion criteria live in
rag-standards (RRF) for the RAG case and in search-engines-standards for the implementation
inside the text engine. Fusion is not decided here.
nosql-standards, graph-db-standards, timeseries-db-standards, data-warehouse-modeling-standards,
lakehouse-standards, streaming-cdc-standards, data-governance-quality-standards,
analytics-bi-standards, caching-cdn-standards, message-brokers-standards,
oracle-dba-standards, sqlserver-dba-standards, mysql-mariadb-dba-standards:
their engines.
data-engineering-standards: the pipeline that feeds the index (orchestration, idempotent
backfill, watermarks). Here only the destination and its write cost.
privacy-engineering-standards: personal data, minimisation, DPIA, right to erasure.
An embedding of personal data is personal data (§5.3): here the technical risk of
inversion and the mechanics of deletion in the engine, there the right and its scope.
llm-app-engineering-standards, mlops-standards, local-inference-standards: the model that
produces the vectors, its serving and its lifecycle. Here only what its output costs to store.
object-storage-standards: S3/MinIO/Ceph as a snapshot destination and as the data layer of the
engines that separate compute from storage.
backup-recovery-standards (backup mechanics, proven restore, immutable repositories) and
bcdr-standards (RTO/RPO derived from the business). Here only what is particular about backing
up an ANN index.
kubernetes-standards (StatefulSets, PVCs, operators), linux-storage-standards (the block layer
under the engine), iac-standards, cicd-standards, sre-practice-standards (SLOs, capacity planning).
identity-access-management-standards (the authorisation model), secrets-management-standards
(the engine's API key), cryptography-pki-standards (TLS), firewall-policy-standards (whether to
expose the port — §5.1), networking-standards, vulnerability-management-standards (CVEs and EOL),
grc-compliance-standards.
aws-standards / azure-standards / gcp-standards: managed equivalents. The sizing and
filtering criteria apply the same; the bill and the service model are theirs.
- Language skills (
python-standards, typescript-standards, go-standards, …): the clients.
2. Default decisions
Verify version, licence and status on the web before committing to anything (§8). A sector with
frequent licence changes and acquisitions; what is verified here is as of August 2026.
2.1 What is this really for? The non-RAG uses
RAG has eaten the conversation, but similarity search is older and broader. Each use has a
different operational profile, and the profile decides the engine far more than fashion does:
| Use |
Load profile |
What decides the design |
| Recommendation ("similar to this", related items) |
Very high reads, relatively stable index, hard latency (it is on the rendering path) |
Read replicas and cache. Recall matters less than p99 |
| Deduplication and record linkage |
Batch loads, similarity threshold, a huge number of queries against the corpus itself |
It is not a top-k problem, it is a threshold problem. The result is reviewed: the vector output is candidates, not a decision. Similarity blocking + deterministic verification afterwards |
| Image / audio / video search |
High-dimensionality vectors, huge corpus, batch writes |
Memory is the problem from day one. Quantisation mandatory, almost always |
| Anomaly detection |
Queries the distance to the nearest neighbour, not the list |
Corpus drift moves the threshold: periodic re-evaluation, or alerts that switch themselves off |
| Clustering / corpus exploration |
Offline batches, no latency SLA |
Almost never needs an online engine: an ANN library in a batch process is enough |
| RAG |
See rag-standards |
— |
Criteria: if the use is offline and batch, an in-process ANN library (FAISS, usearch,
hnswlib) or a columnar file such as Lance solves it without operating a service. A service is
justified by concurrency, online updates and multi-client access, not by having vectors.
2.2 Dedicated engine or pgvector? — the honest question
Inherited from data-platform-standards: one store per need, not per fashion.
| Situation |
Decision |
| You already operate PostgreSQL, moderate volume, relational metadata filtering |
pgvector. Backup, PITR, HA, authentication, RLS, transactionality and monitoring are already solved and already paid for. Adding a dedicated engine is adding a whole operational piece |
| The index does not fit in the PostgreSQL RAM without choking the OLTP |
Dedicated engine, or a separate PostgreSQL instance just for vectors (an intermediate option almost nobody considers) |
| You need advanced quantisation, filtering with a complex payload, or horizontal scaling of the index |
Dedicated engine |
| A corpus of hundreds of millions or billions of vectors |
Dedicated engine with partitioning |
| "It's what people use for AI" |
Not a criterion. Demands an ADR |
The exact threshold is not quoted, it is measured. It depends on dimensionality, quantisation,
filter selectivity, available RAM and target latency — any specific figure you read is someone
else's experiment. Method: load a representative sample (≥10 % of the target corpus),
build the index, measure resident RAM, p95 latency with real filters and build time, and
extrapolate linearly in number of vectors (index memory scales that way; latency, better
than linearly). If the extrapolation does not fit the budget, you have your answer and you have the ADR.
2.3 Engines — verified status (August 2026)
| Engine |
Version |
Licence |
Operational criteria |
| pgvector |
0.8.6 (Jul 2026) |
PostgreSQL (verbatim: "Permission to use, copy, modify, and distribute this software…") |
Default. You operate PostgreSQL, not a new engine |
| Qdrant |
1.18.3 (Jul 2026) |
Apache-2.0 |
Default dedicated engine: good payload filtering, simple operation, clean licence, rich quantisation (§2.5) |
| Weaviate |
1.38.8; 1.39.0-rc.1 (Aug 2026) |
BSD-3-Clause (core, verified in the repo's LICENSE) |
Integrated modules. ⚠️ Anonymous access enabled by default (§5.1) |
| Milvus |
3.0.0 (Jul 2026) and the 2.6.22 series |
Apache-2.0 |
Massive scale in exchange for high operational complexity (several components + etcd + object storage). Recent major: do not adopt 3.x without reading the migration guide |
| Chroma |
tag Latest (Jul 2026); last numbered 1.5.9 (May 2026) |
Apache-2.0 |
Prototyping. Not for serious production (criteria inherited from rag-standards) |
| LanceDB |
0.36/0.37.x (Jul 2026) |
Apache-2.0 |
Columnar format over object storage. Analytical and batch fit; cheap storage instead of expensive RAM is its real proposition |
Vetoed without an ADR: adopting a dedicated engine when you have PostgreSQL and moderate volume;
deploying an engine whose licence you have not read this quarter.
2.4 Index families — what decides a deployment
Tuning parameters and their effect on recall belong to rag-standards §2.3. Here only what
infrastructure pays for: memory and build time.
| Family |
Memory |
Build |
Update / delete |
When |
| Exact (brute force) |
Only the vectors |
None |
Trivial |
Small corpus, or as a reference for measuring the recall of the approximate index. Recall = 1 by definition |
| Graph (HNSW and variants) |
High: vectors + the link graph, and the graph is not negligible |
Slow, and grows more than linearly |
Cheap insertion; deletion degrades the graph (§6.3) |
Default when latency rules and RAM is sufficient |
| IVF (centroid partitioning) |
Lower than graph |
Requires training on representative data already loaded |
Retrain when the distribution changes |
When memory is the constraint and you accept worse recall |
| With quantisation (§2.5) |
The main lever: divides memory by a large factor |
Adds a training phase in PQ; scalar and binary are cheap |
Same as the base family |
When the index does not fit, which is almost always beyond a certain size |
| On disk / hybrid |
Low RAM, high I/O |
Medium |
Medium |
Huge corpus with tolerant latency. Requires NVMe: over network storage it collapses |
Sizing rules that are always forgotten:
- Budget RAM for two indexes, not one: rebuilding without downtime requires the new one to
coexist with the old one. If the node only holds one, you have no hot-rebuild path.
- Build time is either an unavailability window or a double cost. Measure it before
committing to a freshness SLA.
- Dimensionality is paid linearly in everything: storage, index memory, bandwidth
and comparison latency. Reducing it (Matryoshka, PQ) is usually the most profitable cost
optimisation — the choice of model and its dimension belongs to
rag-standards §2.4.
2.5 Quantisation — the cost lever
Verified as of Aug 2026, per engine (§8):
| Engine |
Methods |
Note |
| Qdrant |
TurboQuant (up to 32×), scalar (4×), binary (up to 32×), product (up to 64×) |
The official docs recommend 4-bit TurboQuant over scalar except with Manhattan distance (L1) |
| Weaviate |
RQ (rotational, recommended by the docs), PQ, BQ, SQ, or none |
The docs mention compression by default from a certain version onwards: verify which one applies to yours |
| Milvus |
SQ, PQ, binary and variants |
Verify per version: 3.x changed things |
| pgvector |
halfvec (half precision) and binary quantisation via an expression index |
Less rich than that of the dedicated engines; usually enough |
Hard rules:
- Quantisation is approximation on top of approximation. An ANN index already costs recall;
compressing costs more. Measure recall before and after against brute force (method in
rag-standards §2.3) — never enable it "for efficiency" without the measurement.
- Rescoring with full vectors is what makes aggressive quantisation usable: search
compressed, reorder the candidates at full precision. If your engine supports it, enable it; if
it does not support it, aggressive binary is usually unacceptable.
- Compression factors come from the engine's documentation; the impact on recall comes from your
corpus. The recall numbers vendors publish are measured on academic datasets with
benign distributions. They are not your corpus.
3. The filtering problem — the section that prevents the incident
It is the most common production failure in this domain and it is almost never seen coming, because it
does not raise an error: in development, with 10,000 vectors and no filters, everything works; in
production, with selective filters, the system returns worse results or takes an order of magnitude longer.
The ANN index is built over all of the vector space. A metadata filter
(tenant, date, language, permissions, category) breaks that premise. There are three strategies and
all three fail differently:
| Strategy |
What it does |
How it fails |
| Post-filtering |
Searches the index, filters afterwards |
Returns fewer than k, or nothing. You ask for 10, the index returns 10 global candidates, the filter discards 9 → you are left with 1. With very selective filters, zero results and silence |
| Naive pre-filtering |
Selects by the filter, then searches exactly over the subset |
Correct but can degrade into a full scan if the subset is large. Latency shoots up |
| Filtering during traversal (filterable HNSW, iterative scan, payload indexes) |
The graph traversal applies the filter while navigating |
The right thing, but the graph can become disconnected: if the nodes that pass the filter are not reachable from each other, recall drops silently |
Criteria:
- Know which of the three your engine implements and under what conditions it switches from one
to another. Many engines have heuristics based on estimated selectivity: below a threshold they
do one thing, above it another. That threshold is configurable and almost nobody touches it.
- Measure recall with the filter applied, not without it. 98 % recall without a filter and
40 % with
tenant_id = X is a broken system that passes every test.
- Index the filter fields. A filter with no payload index forces the engine to evaluate
condition by condition during traversal.
- Ultra-selective filters (a small tenant, a specific user) are almost always resolved better
with exact search over the subset than with ANN. If the engine does not decide it by itself, decide it yourself.
- A filter whose selectivity varies a lot between tenants is a latency bomb: p99 will be
set by the worst tenant. Measure per tenant, not in aggregate.
Metadata filtering as a retrieval technique in RAG belongs to rag-standards. Here its
consequence on the index, latency and recall.
4. Quality and gates
| # |
Gate |
Breaks if |
| 1 |
Index recall measured against brute force over a sample, with a non-regression threshold |
It falls below the threshold |
| 2 |
Recall measured with the production filters applied (§3), not only without a filter |
It falls below the threshold |
| 3 |
A change of quantisation, index family or dimensionality ⇒ mandatory recall measurement in the diff |
The measurement is missing |
| 4 |
Proven restore: snapshot restored in a clean environment and queried, with the time recorded |
It does not restore, or the time is not measured |
| 5 |
Declared memory budget (index RAM extrapolated to the target volume) and an alert before exhausting it |
It does not exist |
| 6 |
Authentication and TLS enabled in every network-reachable environment, verified by an automated test that makes a request without credentials and expects 401/403 |
It answers 200 |
| 7 |
Isolation between tenants: a test that one tenant does not retrieve another's vectors (§5.2) |
Leak. Non-negotiable |
| 8 |
Propagated deletion: once a record is deleted, it does not reappear in results after compaction |
It survives |
| 9 |
Index rebuild rehearsed and timed at least once a quarter |
Not rehearsed |
| 10 |
SCA and CVEs of the engine and its clients (§5.4) |
Critical without mitigation |
Gate 6 is the one that saves you most often. A vector engine with an anonymous curl that
returns 200 is a data leak, not a configuration issue.
5. Security
5.1 These engines ship open — verified per engine
The most valuable security fact in this skill. Verified in the official documentation as of Aug 2026:
| Engine |
Default state |
Quote / evidence |
| Qdrant (self-hosted OSS) |
No authentication |
Official docs, verbatim: "By default, all self-deployed Qdrant instances are not secure." and "By default, an open source Qdrant deployment accepts requests from anyone who can reach it." It is closed with service.api_key (and read-only / granular keys). In Qdrant Cloud it is enabled by default |
| Weaviate |
Anonymous access enabled |
Environment variable reference, verbatim: AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED … "Defaults to true". It must be set to false and API key or OIDC enabled explicitly |
| Milvus |
Authentication disabled, and with a known default password |
Official docs, verbatim: "By default, the root user is created with the password Milvus when Milvus is initiated." It is enabled with common.security.authorizationEnabled |
| Chroma |
No authentication in the standard startup |
Port 8000. Auth configuration explicit and optional |
| pgvector |
Inherits PostgreSQL's authentication |
It is its biggest security advantage and almost nobody mentions it: pg_hba.conf, roles, TLS, RLS and auditing already exist and are already reviewed |
| LanceDB (embedded) |
There is no service to authenticate |
The control is the storage's (S3/object IAM). If the bucket is open, the index is open |
Rules:
- No vector engine is exposed to the Internet. Ever. There is no legitimate use case for a port
6333, 19530, 8080 or 8000 of a vector engine reachable from outside. Private network, and a
default-deny firewall rule (firewall-policy-standards).
- Public research (Orca Security, May 2026) documents exposed instances enumerable without
authentication on those default ports, with entire corpora —tickets, knowledge bases,
conversations— accessible. The exact number of instances is not pinned here (§8): what decides
is that the pattern is confirmed and automated.
- The API key is a secret:
secrets-management-standards. Not in docker-compose.yml, not in the
chart, not in the image.
- TLS mandatory inside the perimeter too (
cryptography-pki-standards): the vectors and the
payloads travel in the clear otherwise.
- The metrics endpoint and the web panel are also exposed. Count them when opening ports.
5.2 Multi-tenancy: isolation by collection versus isolation by filter
| Model |
Isolation |
Cost |
Effect on recall |
| Collection (or index) per tenant |
Strong: a boundary, not a condition. Deleting a tenant is deleting a collection |
High with many tenants: each collection has fixed index and memory overhead. Thousands of small tenants do not scale this way |
Better: the index contains only the tenant's data, with no filter to degrade traversal |
tenant_id filter in a shared collection |
Weak: it depends on every query carrying the filter. A path that forgets it is a leak |
Low and uniform |
Worse and variable: it is exactly the problem of §3, and p99 is set by the large tenant |
| Hybrid (collection per large tenant, shared for the long tail) |
Strong where it matters |
Medium |
Acceptable, at the cost of two code paths |
Criteria: if isolation is a regulatory or contractual requirement, separate collection. A
filter is a condition that an if can skip; a collection is a boundary. If you choose a filter,
the filter is injected in a layer the application cannot go around, and gate 7 of §4 proves it
in CI. Per-document access control inside a RAG belongs to rag-standards §5.1.
5.3 Embedding inversion — the specific privacy risk
An embedding is not a hash nor an anonymisation. Inversion attacks exist that reconstruct
the original text fully or partially from the vector, and membership inference attacks
that reveal whether a document was in the corpus.
Operational, not theoretical, consequences:
- A vector derived from personal data is personal data: it enters the record of
processing, classification, retention and the right to erasure
(
privacy-engineering-standards).
- Do not export vectors to third parties or to lower-trust environments "because they are just
numbers". A dump of embeddings is a dump of content.
- Deleting the source without deleting the vector is not deletion (§6.3).
- Minimise before vectorising: what does not enter the corpus cannot be reconstructed.
5.4 Attack surface and supply chain
- The engine enters the patching cycle like any other database. Verified
precedents: Milvus CVE-2025-64513, complete authentication bypass in the Proxy
component exploitable unauthenticated, with full administrative access; fixed in
2.4.24 / 2.5.21 / 2.6.5. pgvector 0.8.2 (Feb 2026) fixed CVE-2026-3172 (parallel HNSW
index builds).
- Indirect risk through integrations: CVE-2026-24477 leaked the Qdrant API key in the clear to
unauthenticated users through an AnythingLLM endpoint. Your engine's key can be leaked by
any piece that uses it.
- Pin the image by digest, not by tag; SBOM and signing (
cicd-standards,
vulnerability-management-standards).
6. Operation
6.1 Persistence and durability — verify it, do not assume it
Several of these engines were born in memory only or with optional persistence and added
durability later. Before putting in data you cannot regenerate, answer in writing:
- What is persisted: the vectors, the index, or both? Many engines persist the vectors and
rebuild the index at startup — that is the cold start (§6.5).
- Is there a write-ahead log? What is lost on a
SIGKILL?
- Is the write a synchronous fsync or deferred? Configurable?
- What consistency guarantee is there between replicas, and what do you see during a node failure?
Golden rule that saves half of these questions: the vector index is a derived projection, not the
source of truth. The original text, the metadata and —if you can afford it— the
vectors live in a durable store (PostgreSQL, object storage). That way, the worst case for the
vector engine is reindexing, not losing data. Design for that from day one and half of this
section stops being critical.
6.2 Backup and restore
- A snapshot of an ANN index is not a
pg_dump. It is usually a consistent copy of binary
segments coupled to the engine version: restoring it on a different version can fail or
degrade silently. Record the version with the snapshot.
- A hot disk snapshot taken without coordinating with the engine can be inconsistent.
Use the engine's own snapshot mechanism, or freeze writes (
fsfreeze and hooks:
backup-recovery-standards).
- The real cost of the backup is the restore, and restoring a large index includes loading it into
memory. Time it (§4, gate 4) and compare it against the committed RTO (
bcdr-standards). It is
common for reindexing from the source of truth to be faster than restoring — if that is your
case, that is your recovery procedure and it has to be written down.
- Destination: object storage with versioning and immutability (
object-storage-standards),
client-side encrypted.
6.3 Updates, deletions and compaction
- Graph indexes degrade with deletion. The usual pattern is to mark (tombstone) and
compact later: between the two, the index occupies memory for vectors that no longer exist and
traversal passes through dead nodes. Recall and latency get worse over time in a corpus with
high turnover.
- Compaction is I/O and CPU intensive: schedule it, observe it and account for its peak. A
very volatile corpus may need periodic rebuilding, not just compaction.
- Updating a vector = delete + insert in almost every engine. Reindexing the same
document repeatedly inflates the index even though the logical number of records does not change. Watch
logical vectors versus physical vectors: if they diverge much, it is time to compact or rebuild.
- In IVF, the distribution changes and the centroids age: recall drops even though nothing fails.
Retraining is a planned operation.
- Deletion and the right to erasure: the deletion must reach the vector, the index, the replicas,
the current snapshots and any cache. A
deleted=true that a filter can forget is not
a deletion (privacy-engineering-standards; mechanics in RAG: rag-standards §6.2).
6.4 Scale
- Read replicas are the easy lever: the load on these systems is usually overwhelmingly
read. They cost full memory per replica — the index is not shared.
- Partitioning (sharding): splits the corpus. Each query goes to all the shards and is
merged, so p99 is set by the slowest shard and adding shards does not reduce latency, only
memory per node. Partition for memory, not for latency.
- Partitioning by a business key (tenant, language, date) is better than partitioning at random
if the queries carry that key: then the query touches one shard and latency does improve.
It is the design decision with the highest return in this section.
- When the index stops fitting in memory there are exactly four ways out, in order of increasing
cost: (1) quantise (§2.5), (2) reduce dimensionality, (3) on-disk index over
NVMe, (4) partition horizontally. Buying RAM is the fifth and not always the worst.
- Rebalancing: moving a shard is moving gigabytes and rebuilding an index. Ask before
deploying how long it takes and whether it can be done without downtime.
6.5 Cold start
The startup time of a vector engine is not that of a process, it is that of loading tens or
hundreds of GB into memory (or rebuilding the index, per §6.1). Consequences that break deployments:
- Liveness/readiness probes with web-service thresholds kill the pod in a loop
(
kubernetes-standards): tune startupProbe.
- A rolling restart of N replicas costs N × startup time, with reduced capacity meanwhile.
- Reactive autoscaling does not work with this profile: by the time the new replica is ready, the
peak has passed. Over-provision or scale on an anticipatory signal.
- Measure it and put it in the runbook. It is the number nobody has when it is needed.
6.6 Cost and observability
Memory is the dominant cost, and it rises through three multiplying paths: number of vectors ×
dimensionality × replicas. The levers, by return: quantisation → dimensionality →
number of replicas → on-disk index.
Instrument (observability-standards covers the transport and the backend):
- Resident RAM of the process versus node RAM — the metric that predicts the outage.
- p50/p95/p99 latency per collection and per tenant, not in aggregate.
- Logical versus physical vectors (compaction debt).
- Write rate, indexing lag, compaction duration.
- Recall measured periodically against brute force over a sample: it is the only alarm that
detects silent degradation. Without it, an index that gets worse produces no signal at all.
- Cold start time and index build time, as historical series.
6.7 Minimum runbook
Index that does not fit in memory (node OOM); latency spiking after adding a filter; recall that
drops with no code change (pending compaction, aged centroids, corpus drift);
snapshot that does not restore on the current version; node that never finishes starting; tenant that sees
another's data (security incident, not a bug: incident-management-standards,
incident-response-forensics-standards); engine discovered exposed without authentication (assume
compromise and treat the corpus as leaked).
7. Sustainability and prohibitions
Review cadence: 3 months. Versions, licences, quantisation methods and CVEs move
quarterly in this sector.
- Review: engine version and CVEs, licence (frequent change pattern), new quantisation
support (methods with a better trade-off appear every few months), and whether the memory
budget still matches the real growth of the corpus.
- Updating the engine may require rebuilding the index or invalidate snapshots. Read it in the
release notes beforehand, not during.
- Recorded conscious debt: recall not measured, restore not proven, pending compaction,
postponed authentication ("it's only on the internal network").
FORBIDDEN
- ❌ Deploying a dedicated vector engine when you have PostgreSQL and moderate volume, without an ADR.
- ❌ Deploying a service for an offline batch use that an in-process ANN library would solve.
- ❌ Exposing the engine's port to the Internet. Under no circumstances.
- ❌ Starting up in any network-reachable environment without authentication or TLS (§5.1). "It's on the
internal network" is not a control.
- ❌ Leaving Milvus's default password (
root/Milvus) or any demo credential.
- ❌ Putting the engine's API key in the
docker-compose.yml, the chart or the image.
- ❌ Pinning index parameters or enabling quantisation without measuring recall against brute force.
- ❌ Measuring recall without the production filters applied and declaring the system good.
- ❌ Trusting post-filtering with selective filters and not noticing that you return fewer than
k.
- ❌ Filtering by a field without a payload index.
- ❌ Sizing RAM for a single index and being left with no hot-rebuild path.
- ❌ Treating the vector index as the source of truth, with no durable source to reindex from.
- ❌ Snapshot without a proven restore and without timing it; snapshot without recording the engine version.
- ❌ Copying the disk hot without using the engine's snapshot mechanism or freezing writes.
- ❌ Ignoring graph degradation from deletion in a corpus with high turnover.
- ❌ Logical deletion as an answer to a right to erasure.
- ❌ Treating an embedding as anonymisation, or exporting it to a lower-trust environment.
- ❌ Multi-tenancy by filter when isolation is a regulatory requirement, or without an isolation
test in CI.
- ❌ Startup probes with web-service thresholds over an engine that loads GB into memory.
- ❌ Reactive autoscaling as the capacity plan of an engine with a long cold start.
- ❌ Chroma in serious production; adopting Milvus 3.x without reading the migration guide.
- ❌ Duplicating
rag-standards criteria here (chunking, embeddings, ANN tuning, hybrid, RRF,
reranking, recall@k) instead of linking to them.
- ❌ Pinning a version, a licence, a compression factor or a recall figure from memory (§8).
8. Mandatory web verification
- Version and licence of each engine: pgvector, Qdrant, Weaviate, Milvus, Chroma, LanceDB.
Verified as of Aug 2026 via release Atom feeds and the repository's
LICENSE files (not via
summaries of HTML pages, which invent dates): pgvector 0.8.6 / PostgreSQL licence;
Qdrant 1.18.3 / Apache-2.0; Weaviate 1.38.8 and 1.39.0-rc.1 / BSD-3-Clause confirmed in the
core's LICENSE; Milvus 3.0.0 and 2.6.22 / Apache-2.0; Chroma / Apache-2.0; LanceDB
0.36-0.37.x / Apache-2.0. Re-verify: licence change is the sector's pattern.
- CVEs: Milvus CVE-2025-64513 (unauthenticated auth bypass, fixed in 2.4.24/2.5.21/
2.6.5), pgvector CVE-2026-3172 (fixed in 0.8.2), CVE-2026-24477 (leak of the Qdrant API
key via AnythingLLM). Check for new advisories before pinning a version.
- Default authentication per engine (§5.1). Verified verbatim in official documentation for
Qdrant, Weaviate and Milvus. Re-verify it on every major version: it is the fact that changes
most and the one that costs most if it is wrong.
- Quantisation support per engine and version (§2.5), and whether there is rescoring with full vectors.
- Persistence model of the specific engine (§6.1): what is persisted, WAL, fsync, and whether the index
is rebuilt at startup.
- Snapshot compatibility between versions before any update.
- Equivalent managed services and their pricing model (
aws-standards, azure-standards,
gcp-standards) — they change often.
- Supply-chain incidents in the ecosystem (precedents in the catalogue: LiteLLM on
PyPI, March 2026).
Declared gaps — do NOT fill in from memory:
- Exact volume threshold at which pgvector stops being enough: deliberately not pinned. It depends
on dimensionality, quantisation, filter selectivity, RAM and target latency. It is measured with
the method of §2.2.
- Memory consumption formulas per index family: not pinned. The ones in circulation omit the
real overhead of the graph and the payload. Measure it over a sample.
- Impact on recall of each quantisation method: not pinned. The compression factors come
from the vendor's documentation (verified); recall depends on your corpus and your model.
- Quantisation in Milvus 3.x: not verified in detail in this review (the major is from Jul 2026).
Consult its documentation before pinning anything.
- Default auth status of Chroma and LanceDB: verified only indirectly (Chroma without
auth in the standard startup, port 8000; embedded LanceDB exposes no service). Confirm it in their
documentation before deploying.
- Figures for instances exposed on the Internet: the pattern is confirmed by public research
(Orca Security, May 2026); the specific counts circulating in blogs are not quoted as facts.
- Latencies, throughput and comparative benchmarks between engines: not pinned. The public ones are almost
always from vendors, without reproducible conditions and over academic datasets.
- Prices of the managed services: not pinned.
If the web contradicts this document, the web wins — flag the discrepancy.
1---2name: vector-db-standards3description: Operating a vector search engine as a piece of infrastructure. Use when sizing RAM and disk for an ANN index, choosing binary, scalar, product or rotational/RaBitQ-style vector compression, diagnosing a selective pre-filter or post-filter that collapses recall or latency, collection snapshots and restoring an index, index build and rebuild time, cold start after restart, replication factor, shards and horizontal partitioning of collections, tombstones and graph degradation after deletes, per-collection versus per-filter tenant isolation, securing engines that ship open (Qdrant service.api_key, AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED, Milvus authorizationEnabled and the default root password, ports 6333/6334, 19530, 8080, 8000), embedding inversion as a privacy risk, or non-RAG similarity workloads such as recommendation, deduplication and record linkage, image or audio search, anomaly detection and clustering.4---56# Vector database standards (the engine as infrastructure)78Criteria verified as of **August 2026**. Re-verify on the web before committing to anything (§8).910## 1. Scope and triggers1112Applies when you have to **deploy, operate, size, back up, scale, secure or pay for** a vector13search engine: the decision of whether a dedicated engine is needed at all, the14recall/latency/memory trade-off as an explicit decision, the RAM cost and build time of each15index family, pre-/post-filtering, index persistence and backup, rebuilding, deletion and graph16degradation, replicas and partitioning, multi-tenancy, and the uses of vector similarity **that are17not RAG**.1819Triggers: "do I need a vector database?", "it doesn't fit in memory", "how much RAM does the index20need", "binary/scalar/product quantisation", "compress vectors", "collection snapshot",21"restore an index", "how long does a rebuild take", "cold start", "the engine takes ages to come22up", "replication factor", "collection sharding", "deletion and compaction",23"tombstones", "recall dropped when I added a filter", "the filter returns fewer results than I24ask for", "isolation by collection or by filter", "one tenant per collection", "endpoint with no25authentication", `service.api_key`, `AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED`,26`authorizationEnabled`, ports `6333`/`6334`, `19530`, `8080`, `8000`, "embedding inversion",27"deduplication", "record linkage", "image search", "anomaly detection", "clustering",28"similarity-based recommendation".2930**Domain thesis**: *a vector engine is a database that lives in RAM and answers with31approximations.* The two halves of that sentence decide everything else: **memory is the dominant32resource and the real cost**, and **recall is not a fact, it is a parameter you have chosen —33consciously or unconsciously**.3435**Arbitration rule with `rag-standards` (read it before writing anything in this domain)**: if the36question changes **what is retrieved**, it belongs to `rag-standards`; if it changes **who operates,37pays for, backs up or restores the engine**, it belongs here. Operational corollary: raising38`ef_search` to improve the recall of a RAG belongs to `rag-standards`; the node that runs out of RAM39building that index, or the restore that takes six hours, belongs here.4041**Not applicable**:4243- **`rag-standards`** — **the critical boundary**. It is **the retrieval pattern for feeding an44 LLM**: chunking, choice and lifecycle of the embedding model and its reindexing cost,45 choosing between pgvector and a dedicated engine **from the perspective of retrieval quality**,46 **HNSW and IVFFlat tuning parameters** (`m`, `ef_construction`, `ef_search`, `lists`,47 `probes`), hybrid dense + BM25 retrieval with **RRF fusion**, cross-encoder reranking,48 metadata filtering as a retrieval technique, `recall@k`/`MRR`/`nDCG` metrics, and per-document49 access control in retrieval. **None of that is repeated here**: when this skill50 needs those concepts, it links to them. Here, the engine as a piece of infrastructure and the51 non-RAG uses.52- `data-platform-standards` — **parent skill**: the PostgreSQL engine (modelling, migrations, replicas,53 PITR, tuning, RLS, JSONB, full-text) and the guiding principle **"one store per need, not per fashion"**,54 which this skill inherits whole. **Three-way arbitration for `pgvector`**: the extension and its index55 parameters belong to `rag-standards`; **the PostgreSQL that hosts it, its backup, its HA and its patching56 belong to `data-platform-standards`**; the criteria for **when pgvector stops being enough and what it57 costs to operate the dedicated piece that replaces it** belong here (§2.2).58- `search-engines-standards` — text engines (Elasticsearch/OpenSearch, Meilisearch, Typesense,59 Vespa, Solr), inverted index modelling, BM25 relevance, index lifecycle and cluster60 operation. **Several of them also do vector search**: if the engine is already deployed61 for its lexical capability, the criteria for operating it are theirs; if it is deployed **for** the62 vectors, they belong here. **Hybrid search crosses all three skills: the fusion criteria live in63 `rag-standards` (RRF) for the RAG case and in `search-engines-standards` for the implementation64 inside the text engine. Fusion is not decided here.**65- `nosql-standards`, `graph-db-standards`, `timeseries-db-standards`, `data-warehouse-modeling-standards`,66 `lakehouse-standards`, `streaming-cdc-standards`, `data-governance-quality-standards`,67 `analytics-bi-standards`, `caching-cdn-standards`, `message-brokers-standards`,68 `oracle-dba-standards`, `sqlserver-dba-standards`, `mysql-mariadb-dba-standards`:69 their engines.70- `data-engineering-standards`: the pipeline that feeds the index (orchestration, idempotent71 backfill, watermarks). Here only the destination and its write cost.72- `privacy-engineering-standards`: personal data, minimisation, DPIA, right to erasure.73 **An embedding of personal data is personal data** (§5.3): here the technical risk of74 inversion and the mechanics of deletion in the engine, there the right and its scope.75- `llm-app-engineering-standards`, `mlops-standards`, `local-inference-standards`: the model that76 produces the vectors, its serving and its lifecycle. Here only what its output costs to store.77- `object-storage-standards`: S3/MinIO/Ceph as a snapshot destination and as the data layer of the78 engines that separate compute from storage.79- `backup-recovery-standards` (backup mechanics, proven restore, immutable repositories) and80 `bcdr-standards` (RTO/RPO derived from the business). Here only **what is particular about backing81 up an ANN index**.82- `kubernetes-standards` (StatefulSets, PVCs, operators), `linux-storage-standards` (the block layer83 under the engine), `iac-standards`, `cicd-standards`, `sre-practice-standards` (SLOs, capacity planning).84- `identity-access-management-standards` (the authorisation model), `secrets-management-standards`85 (the engine's API key), `cryptography-pki-standards` (TLS), `firewall-policy-standards` (whether to86 expose the port — §5.1), `networking-standards`, `vulnerability-management-standards` (CVEs and EOL),87 `grc-compliance-standards`.88- `aws-standards` / `azure-standards` / `gcp-standards`: managed equivalents. The sizing and89 filtering criteria apply the same; the bill and the service model are theirs.90- Language skills (`python-standards`, `typescript-standards`, `go-standards`, …): the clients.9192## 2. Default decisions9394> Verify version, licence and status on the web before committing to anything (§8). A sector with95> **frequent licence changes and acquisitions**; what is verified here is as of August 2026.9697### 2.1 What is this really for? The non-RAG uses9899RAG has eaten the conversation, but similarity search is older and broader. Each use has a100different operational profile, and **the profile decides the engine far more than fashion does**:101102| Use | Load profile | What decides the design |103|---|---|---|104| **Recommendation** ("similar to this", *related items*) | Very high reads, relatively stable index, hard latency (it is on the rendering path) | Read replicas and cache. Recall matters less than p99 |105| **Deduplication and *record linkage*** | Batch loads, similarity threshold, a huge number of queries against the corpus itself | **It is not a top-k problem, it is a threshold problem.** The result is reviewed: the vector output is *candidates*, not a decision. Similarity blocking + deterministic verification afterwards |106| **Image / audio / video search** | High-dimensionality vectors, huge corpus, batch writes | Memory is the problem from day one. Quantisation mandatory, almost always |107| **Anomaly detection** | Queries the distance to the nearest neighbour, not the list | Corpus *drift* moves the threshold: periodic re-evaluation, or alerts that switch themselves off |108| **Clustering / corpus exploration** | Offline batches, no latency SLA | Almost never needs an online engine: an ANN library in a batch process is enough |109| **RAG** | See `rag-standards` | — |110111**Criteria**: if the use is **offline and batch**, an in-process ANN library (FAISS, `usearch`,112`hnswlib`) or a columnar file such as Lance solves it without operating a service. **A service is113justified by concurrency, online updates and multi-client access, not by having vectors.**114115### 2.2 Dedicated engine or pgvector? — the honest question116117Inherited from `data-platform-standards`: **one store per need, not per fashion.**118119| Situation | Decision |120|---|---|121| You already operate PostgreSQL, moderate volume, relational metadata filtering | **`pgvector`.** Backup, PITR, HA, authentication, RLS, transactionality and monitoring **are already solved and already paid for**. Adding a dedicated engine is adding a whole operational piece |122| The index does not fit in the PostgreSQL RAM without choking the OLTP | Dedicated engine, **or** a separate PostgreSQL instance just for vectors (an intermediate option almost nobody considers) |123| You need advanced quantisation, filtering with a complex payload, or horizontal scaling of the index | Dedicated engine |124| A corpus of hundreds of millions or billions of vectors | Dedicated engine with partitioning |125| "It's what people use for AI" | **Not a criterion.** Demands an ADR |126127**The exact threshold is not quoted, it is measured.** It depends on dimensionality, quantisation,128filter selectivity, available RAM and target latency — any specific figure you read is someone129else's experiment. **Method**: load a representative sample (≥10 % of the target corpus),130build the index, measure resident RAM, p95 latency with real filters and build time, and131**extrapolate linearly in number of vectors** (index memory scales that way; latency, better132than linearly). If the extrapolation does not fit the budget, you have your answer and you have the ADR.133134### 2.3 Engines — verified status (August 2026)135136| Engine | Version | Licence | Operational criteria |137|---|---|---|---|138| **pgvector** | **0.8.6** (Jul 2026) | **PostgreSQL** (verbatim: *"Permission to use, copy, modify, and distribute this software…"*) | Default. You operate PostgreSQL, not a new engine |139| **Qdrant** | **1.18.3** (Jul 2026) | **Apache-2.0** | Default dedicated engine: good payload filtering, simple operation, clean licence, rich quantisation (§2.5) |140| **Weaviate** | **1.38.8**; **1.39.0-rc.1** (Aug 2026) | **BSD-3-Clause** (core, verified in the repo's `LICENSE`) | Integrated modules. ⚠️ **Anonymous access enabled by default** (§5.1) |141| **Milvus** | **3.0.0** (Jul 2026) and the **2.6.22** series | **Apache-2.0** | Massive scale in exchange for high operational complexity (several components + etcd + object storage). **Recent major: do not adopt 3.x without reading the migration guide** |142| **Chroma** | tag `Latest` (Jul 2026); last numbered **1.5.9** (May 2026) | **Apache-2.0** | Prototyping. **Not for serious production** (criteria inherited from `rag-standards`) |143| **LanceDB** | **0.36/0.37.x** (Jul 2026) | **Apache-2.0** | Columnar format over object storage. Analytical and batch fit; **cheap storage instead of expensive RAM** is its real proposition |144145**Vetoed without an ADR**: adopting a dedicated engine when you have PostgreSQL and moderate volume;146deploying an engine whose licence you have not read this quarter.147148### 2.4 Index families — what decides a deployment149150Tuning parameters and their effect on recall belong to `rag-standards` §2.3. **Here only what151infrastructure pays for: memory and build time.**152153| Family | Memory | Build | Update / delete | When |154|---|---|---|---|---|155| **Exact (brute force)** | Only the vectors | None | Trivial | Small corpus, or **as a reference for measuring the recall of the approximate index**. Recall = 1 by definition |156| **Graph (HNSW and variants)** | **High**: vectors **+ the link graph**, and the graph is not negligible | Slow, and grows more than linearly | Cheap insertion; **deletion degrades the graph** (§6.3) | Default when latency rules and RAM is sufficient |157| **IVF (centroid partitioning)** | Lower than graph | **Requires training on representative data already loaded** | Retrain when the distribution changes | When memory is the constraint and you accept worse recall |158| **With quantisation** (§2.5) | **The main lever**: divides memory by a large factor | Adds a training phase in PQ; scalar and binary are cheap | Same as the base family | When the index does not fit, which is almost always beyond a certain size |159| **On disk / hybrid** | Low RAM, high I/O | Medium | Medium | Huge corpus with tolerant latency. **Requires NVMe: over network storage it collapses** |160161**Sizing rules that are always forgotten**:1621631. **Budget RAM for two indexes, not one**: rebuilding without downtime requires the new one to164 coexist with the old one. If the node only holds one, you have no hot-rebuild path.1652. **Build time is either an unavailability window or a double cost.** Measure it before166 committing to a freshness SLA.1673. **Dimensionality is paid linearly in everything**: storage, index memory, bandwidth168 and comparison latency. Reducing it (Matryoshka, PQ) is usually the most profitable cost169 optimisation — the choice of model and its dimension belongs to `rag-standards` §2.4.170171### 2.5 Quantisation — the cost lever172173Verified as of Aug 2026, **per engine** (§8):174175| Engine | Methods | Note |176|---|---|---|177| **Qdrant** | **TurboQuant** (up to 32×), **scalar** (4×), **binary** (up to 32×), **product** (up to 64×) | The official docs recommend 4-bit TurboQuant over scalar except with Manhattan distance (L1) |178| **Weaviate** | **RQ (rotational, recommended by the docs)**, **PQ**, **BQ**, **SQ**, or none | The docs mention compression by default from a certain version onwards: **verify which one applies to yours** |179| **Milvus** | SQ, PQ, binary and variants | Verify per version: 3.x changed things |180| **pgvector** | `halfvec` (half precision) and binary quantisation via an expression index | Less rich than that of the dedicated engines; usually enough |181182**Hard rules**:183184- **Quantisation is approximation on top of approximation.** An ANN index already costs recall;185 compressing costs more. **Measure recall before and after against brute force** (method in186 `rag-standards` §2.3) — never enable it "for efficiency" without the measurement.187- ***Rescoring* with full vectors is what makes aggressive quantisation usable**: search188 compressed, reorder the candidates at full precision. If your engine supports it, enable it; if189 it does not support it, aggressive binary is usually unacceptable.190- **Compression factors come from the engine's documentation; the impact on recall comes from your191 corpus.** The recall numbers vendors publish are measured on academic datasets with192 benign distributions. They are not your corpus.193194## 3. The filtering problem — the section that prevents the incident195196**It is the most common production failure in this domain** and it is almost never seen coming, because **it197does not raise an error**: in development, with 10,000 vectors and no filters, everything works; in198production, with selective filters, the system returns worse results or takes an order of magnitude longer.199200The ANN index is built over **all** of the vector space. A metadata filter201(tenant, date, language, permissions, category) breaks that premise. There are three strategies and202all three fail differently:203204| Strategy | What it does | How it fails |205|---|---|---|206| **Post-filtering** | Searches the index, filters afterwards | **Returns fewer than `k`, or nothing.** You ask for 10, the index returns 10 global candidates, the filter discards 9 → you are left with 1. With very selective filters, zero results and silence |207| **Naive pre-filtering** | Selects by the filter, then searches exactly over the subset | Correct but **can degrade into a full scan** if the subset is large. Latency shoots up |208| **Filtering during traversal** (*filterable HNSW*, *iterative scan*, payload indexes) | The graph traversal applies the filter while navigating | The right thing, but **the graph can become disconnected**: if the nodes that pass the filter are not reachable from each other, recall drops silently |209210**Criteria**:2112121. **Know which of the three your engine implements and under what conditions it switches from one213 to another.** Many engines have heuristics based on estimated selectivity: below a threshold they214 do one thing, above it another. That threshold is configurable and almost nobody touches it.2152. **Measure recall *with the filter applied*, not without it.** 98 % recall without a filter and216 40 % with `tenant_id = X` is a broken system that passes every test.2173. **Index the filter fields.** A filter with no payload index forces the engine to evaluate218 condition by condition during traversal.2194. **Ultra-selective filters (a small tenant, a specific user) are almost always resolved better220 with exact search over the subset** than with ANN. If the engine does not decide it by itself, decide it yourself.2215. **A filter whose selectivity varies a lot between tenants is a latency bomb**: p99 will be222 set by the worst tenant. Measure per tenant, not in aggregate.223224**Metadata filtering *as a retrieval technique in RAG* belongs to `rag-standards`.** Here its225consequence on the index, latency and recall.226227## 4. Quality and gates228229| # | Gate | Breaks if |230|---|---|---|231| 1 | **Index recall measured against brute force** over a sample, with a non-regression threshold | It falls below the threshold |232| 2 | **Recall measured *with the production filters applied*** (§3), not only without a filter | It falls below the threshold |233| 3 | **A change of quantisation, index family or dimensionality ⇒ mandatory recall measurement** in the diff | The measurement is missing |234| 4 | **Proven restore**: snapshot restored in a clean environment and queried, with the time recorded | It does not restore, or the time is not measured |235| 5 | **Declared memory budget** (index RAM extrapolated to the target volume) and an alert before exhausting it | It does not exist |236| 6 | **Authentication and TLS enabled in every network-reachable environment**, verified by an automated test that makes a request **without credentials** and expects `401`/`403` | It answers `200` |237| 7 | **Isolation between tenants**: a test that one tenant does not retrieve another's vectors (§5.2) | Leak. **Non-negotiable** |238| 8 | **Propagated deletion**: once a record is deleted, it does not reappear in results after compaction | It survives |239| 9 | Index rebuild rehearsed and **timed** at least once a quarter | Not rehearsed |240| 10 | SCA and CVEs of the engine and its clients (§5.4) | Critical without mitigation |241242**Gate 6 is the one that saves you most often.** A vector engine with an anonymous `curl` that243returns `200` is a data leak, not a configuration issue.244245## 5. Security246247### 5.1 These engines ship open — verified per engine248249**The most valuable security fact in this skill.** Verified in the official documentation as of Aug 2026:250251| Engine | Default state | Quote / evidence |252|---|---|---|253| **Qdrant** (self-hosted OSS) | **No authentication** | Official docs, verbatim: *"By default, all self-deployed Qdrant instances are not secure."* and *"By default, an open source Qdrant deployment accepts requests from anyone who can reach it."* It is closed with `service.api_key` (and read-only / granular keys). In Qdrant Cloud it is enabled by default |254| **Weaviate** | **Anonymous access enabled** | Environment variable reference, verbatim: `AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED` … *"Defaults to true"*. It must be set to `false` and API key or OIDC enabled explicitly |255| **Milvus** | **Authentication disabled**, and with a **known default password** | Official docs, verbatim: *"By default, the `root` user is created with the password `Milvus` when Milvus is initiated."* It is enabled with `common.security.authorizationEnabled` |256| **Chroma** | No authentication in the standard startup | Port `8000`. Auth configuration explicit and optional |257| **pgvector** | **Inherits PostgreSQL's authentication** | **It is its biggest security advantage and almost nobody mentions it**: `pg_hba.conf`, roles, TLS, RLS and auditing already exist and are already reviewed |258| **LanceDB** (embedded) | There is no service to authenticate | The control is the storage's (S3/object IAM). **If the bucket is open, the index is open** |259260**Rules**:261262- **No vector engine is exposed to the Internet. Ever.** There is no legitimate use case for a port263 `6333`, `19530`, `8080` or `8000` of a vector engine reachable from outside. Private network, and a264 default-deny firewall rule (`firewall-policy-standards`).265- **Public research (Orca Security, May 2026)** documents exposed instances enumerable without266 authentication on those default ports, with entire corpora —tickets, knowledge bases,267 conversations— accessible. **The exact number of instances is not pinned here** (§8): what decides268 is that the pattern is confirmed and automated.269- **The API key is a secret**: `secrets-management-standards`. Not in `docker-compose.yml`, not in the270 chart, not in the image.271- **TLS mandatory** inside the perimeter too (`cryptography-pki-standards`): the vectors and the272 payloads travel in the clear otherwise.273- **The metrics endpoint and the web panel are also exposed.** Count them when opening ports.274275### 5.2 Multi-tenancy: isolation by collection versus isolation by filter276277| Model | Isolation | Cost | Effect on recall |278|---|---|---|---|279| **Collection (or index) per tenant** | **Strong**: a boundary, not a condition. Deleting a tenant is deleting a collection | High with many tenants: each collection has fixed index and memory overhead. Thousands of small tenants do not scale this way | **Better**: the index contains only the tenant's data, with no filter to degrade traversal |280| **`tenant_id` filter in a shared collection** | **Weak**: it depends on **every** query carrying the filter. A path that forgets it is a leak | Low and uniform | **Worse and variable**: it is exactly the problem of §3, and p99 is set by the large tenant |281| **Hybrid** (collection per large tenant, shared for the long tail) | Strong where it matters | Medium | Acceptable, at the cost of two code paths |282283**Criteria**: **if isolation is a regulatory or contractual requirement, separate collection.** A284filter is a condition that an `if` can skip; a collection is a boundary. If you choose a filter,285the filter is injected **in a layer the application cannot go around**, and gate 7 of §4 proves it286in CI. **Per-document** access control inside a RAG belongs to `rag-standards` §5.1.287288### 5.3 Embedding inversion — the specific privacy risk289290**An embedding is not a hash nor an anonymisation.** Inversion attacks exist that reconstruct291the original text fully or partially from the vector, and membership inference attacks292that reveal whether a document was in the corpus.293294Operational, not theoretical, consequences:295296- **A vector derived from personal data is personal data**: it enters the record of297 processing, classification, retention and the right to erasure298 (`privacy-engineering-standards`).299- **Do not export vectors to third parties or to lower-trust environments "because they are just300 numbers".** A dump of embeddings is a dump of content.301- **Deleting the source without deleting the vector is not deletion** (§6.3).302- Minimise before vectorising: what does not enter the corpus cannot be reconstructed.303304### 5.4 Attack surface and supply chain305306- **The engine enters the patching cycle like any other database.** Verified307 precedents: **Milvus CVE-2025-64513**, complete authentication *bypass* in the Proxy308 component exploitable **unauthenticated**, with full administrative access; fixed in309 2.4.24 / 2.5.21 / 2.6.5. **pgvector 0.8.2 (Feb 2026) fixed CVE-2026-3172** (parallel HNSW310 index builds).311- Indirect risk through integrations: **CVE-2026-24477** leaked the Qdrant API key in the clear to312 unauthenticated users through an AnythingLLM endpoint. **Your engine's key can be leaked by313 any piece that uses it.**314- Pin the image by **digest**, not by tag; SBOM and signing (`cicd-standards`,315 `vulnerability-management-standards`).316317## 6. Operation318319### 6.1 Persistence and durability — verify it, do not assume it320321Several of these engines were born **in memory only** or with optional persistence and added322durability later. **Before putting in data you cannot regenerate, answer in writing**:3233241. What is persisted: the vectors, the index, or both? Many engines persist the vectors and325 **rebuild the index at startup** — that is the cold start (§6.5).3262. Is there a *write-ahead log*? What is lost on a `SIGKILL`?3273. Is the write a synchronous *fsync* or deferred? Configurable?3284. What consistency guarantee is there between replicas, and what do you see during a node failure?329330**Golden rule that saves half of these questions: the vector index is a derived projection, not the331source of truth.** The original text, the metadata and —if you can afford it— the332vectors live in a durable store (PostgreSQL, object storage). That way, **the worst case for the333vector engine is reindexing, not losing data.** Design for that from day one and half of this334section stops being critical.335336### 6.2 Backup and restore337338- **A snapshot of an ANN index is not a `pg_dump`.** It is usually a consistent copy of binary339 segments coupled to the **engine version**: restoring it on a different version can fail or340 degrade silently. **Record the version with the snapshot.**341- **A hot disk snapshot taken without coordinating with the engine can be inconsistent.**342 Use the engine's own snapshot mechanism, or freeze writes (`fsfreeze` and hooks:343 `backup-recovery-standards`).344- **The real cost of the backup is the restore, and restoring a large index includes loading it into345 memory.** Time it (§4, gate 4) and compare it against the committed RTO (`bcdr-standards`). It is346 common for **reindexing from the source of truth to be faster than restoring** — if that is your347 case, that is your recovery procedure and it has to be written down.348- Destination: object storage with versioning and immutability (`object-storage-standards`),349 client-side encrypted.350351### 6.3 Updates, deletions and compaction352353- **Graph indexes degrade with deletion.** The usual pattern is to mark (*tombstone*) and354 compact later: between the two, the index occupies memory for vectors that no longer exist and355 traversal passes through dead nodes. **Recall and latency get worse over time in a corpus with356 high turnover.**357- **Compaction is I/O and CPU intensive**: schedule it, observe it and account for its peak. A358 very volatile corpus may need **periodic rebuilding**, not just compaction.359- **Updating a vector = delete + insert** in almost every engine. Reindexing the same360 document repeatedly inflates the index even though the logical number of records does not change. Watch361 **logical vectors versus physical vectors**: if they diverge much, it is time to compact or rebuild.362- **In IVF, the distribution changes and the centroids age**: recall drops even though nothing fails.363 Retraining is a planned operation.364- **Deletion and the right to erasure**: the deletion must reach the vector, the index, the replicas,365 the current snapshots and any cache. A `deleted=true` that a filter can forget **is not366 a deletion** (`privacy-engineering-standards`; mechanics in RAG: `rag-standards` §6.2).367368### 6.4 Scale369370- **Read replicas** are the easy lever: the load on these systems is usually overwhelmingly371 read. They cost **full memory per replica** — the index is not shared.372- **Partitioning (sharding)**: splits the corpus. Each query goes to **all** the shards and is373 merged, so **p99 is set by the slowest shard** and adding shards does not reduce latency, only374 memory per node. **Partition for memory, not for latency.**375- **Partitioning by a business key (tenant, language, date)** is better than partitioning at random376 **if the queries carry that key**: then the query touches one shard and latency does improve.377 It is the design decision with the highest return in this section.378- **When the index stops fitting in memory** there are exactly four ways out, in order of increasing379 cost: **(1)** quantise (§2.5), **(2)** reduce dimensionality, **(3)** on-disk index over380 NVMe, **(4)** partition horizontally. Buying RAM is the fifth and not always the worst.381- **Rebalancing**: moving a shard is moving gigabytes and rebuilding an index. Ask **before**382 deploying how long it takes and whether it can be done without downtime.383384### 6.5 Cold start385386**The startup time of a vector engine is not that of a process, it is that of loading tens or387hundreds of GB into memory** (or rebuilding the index, per §6.1). Consequences that break deployments:388389- *Liveness*/*readiness* probes with web-service thresholds **kill the pod in a loop**390 (`kubernetes-standards`): tune `startupProbe`.391- A rolling restart of N replicas costs N × startup time, with reduced capacity meanwhile.392- **Reactive autoscaling does not work** with this profile: by the time the new replica is ready, the393 peak has passed. Over-provision or scale on an anticipatory signal.394- Measure it and put it in the runbook. It is the number nobody has when it is needed.395396### 6.6 Cost and observability397398**Memory is the dominant cost**, and it rises through three multiplying paths: number of vectors ×399dimensionality × replicas. The levers, by return: **quantisation → dimensionality →400number of replicas → on-disk index**.401402Instrument (`observability-standards` covers the transport and the backend):403404- **Resident RAM of the process versus node RAM** — the metric that predicts the outage.405- p50/p95/p99 latency **per collection and per tenant**, not in aggregate.406- **Logical versus physical vectors** (compaction debt).407- Write rate, indexing lag, compaction duration.408- **Recall measured periodically against brute force over a sample**: it is the only alarm that409 detects silent degradation. **Without it, an index that gets worse produces no signal at all.**410- Cold start time and index build time, as historical series.411412### 6.7 Minimum runbook413414Index that does not fit in memory (node OOM); latency spiking after adding a filter; recall that415drops with no code change (pending compaction, aged centroids, corpus drift);416snapshot that does not restore on the current version; node that never finishes starting; tenant that sees417another's data (**security incident**, not a bug: `incident-management-standards`,418`incident-response-forensics-standards`); engine discovered exposed without authentication (assume419compromise and treat the corpus as leaked).420421## 7. Sustainability and prohibitions422423**Review cadence: 3 months.** Versions, licences, quantisation methods and CVEs move424quarterly in this sector.425426- Review: engine version and CVEs, **licence** (frequent change pattern), new quantisation427 support (methods with a better trade-off appear every few months), and whether the memory428 budget still matches the real growth of the corpus.429- **Updating the engine may require rebuilding the index or invalidate snapshots.** Read it in the430 release notes beforehand, not during.431- Recorded conscious debt: recall not measured, restore not proven, pending compaction,432 postponed authentication ("it's only on the internal network").433434**FORBIDDEN**435436- ❌ Deploying a dedicated vector engine when you have PostgreSQL and moderate volume, without an ADR.437- ❌ Deploying a service for an **offline batch** use that an in-process ANN library would solve.438- ❌ **Exposing the engine's port to the Internet.** Under no circumstances.439- ❌ **Starting up in any network-reachable environment without authentication or TLS** (§5.1). "It's on the440 internal network" is not a control.441- ❌ Leaving Milvus's default password (`root`/`Milvus`) or any demo credential.442- ❌ Putting the engine's API key in the `docker-compose.yml`, the chart or the image.443- ❌ **Pinning index parameters or enabling quantisation without measuring recall against brute force.**444- ❌ **Measuring recall without the production filters applied** and declaring the system good.445- ❌ Trusting post-filtering with selective filters and not noticing that you return fewer than `k`.446- ❌ Filtering by a field without a payload index.447- ❌ Sizing RAM for a single index and being left with no hot-rebuild path.448- ❌ Treating the vector index as the source of truth, with no durable source to reindex from.449- ❌ Snapshot without a proven restore and **without timing it**; snapshot without recording the engine version.450- ❌ Copying the disk hot without using the engine's snapshot mechanism or freezing writes.451- ❌ Ignoring graph degradation from deletion in a corpus with high turnover.452- ❌ Logical deletion as an answer to a right to erasure.453- ❌ **Treating an embedding as anonymisation**, or exporting it to a lower-trust environment.454- ❌ Multi-tenancy by filter when isolation is a regulatory requirement, or without an isolation455 test in CI.456- ❌ Startup probes with web-service thresholds over an engine that loads GB into memory.457- ❌ Reactive autoscaling as the capacity plan of an engine with a long cold start.458- ❌ Chroma in serious production; adopting Milvus 3.x without reading the migration guide.459- ❌ Duplicating `rag-standards` criteria here (chunking, embeddings, ANN tuning, hybrid, RRF,460 reranking, `recall@k`) instead of linking to them.461- ❌ Pinning a version, a licence, a compression factor or a recall figure from memory (§8).462463## 8. Mandatory web verification4644651. **Version and licence of each engine**: pgvector, Qdrant, Weaviate, Milvus, Chroma, LanceDB.466 Verified as of Aug 2026 via release Atom feeds and the repository's `LICENSE` files (not via467 summaries of HTML pages, which **invent dates**): pgvector 0.8.6 / PostgreSQL licence;468 Qdrant 1.18.3 / Apache-2.0; Weaviate 1.38.8 and 1.39.0-rc.1 / **BSD-3-Clause confirmed in the469 core's `LICENSE`**; Milvus **3.0.0** and 2.6.22 / Apache-2.0; Chroma / Apache-2.0; LanceDB470 0.36-0.37.x / Apache-2.0. **Re-verify: licence change is the sector's pattern.**4712. **CVEs**: Milvus **CVE-2025-64513** (unauthenticated auth bypass, fixed in 2.4.24/2.5.21/472 2.6.5), pgvector **CVE-2026-3172** (fixed in 0.8.2), **CVE-2026-24477** (leak of the Qdrant API473 key via AnythingLLM). Check for new advisories before pinning a version.4743. **Default authentication per engine** (§5.1). Verified verbatim in official documentation for475 Qdrant, Weaviate and Milvus. **Re-verify it on every major version: it is the fact that changes476 most and the one that costs most if it is wrong.**4774. **Quantisation support per engine and version** (§2.5), and whether there is *rescoring* with full vectors.4785. **Persistence model** of the specific engine (§6.1): what is persisted, WAL, fsync, and whether the index479 is rebuilt at startup.4806. **Snapshot compatibility between versions** before any update.4817. **Equivalent managed services** and their pricing model (`aws-standards`, `azure-standards`,482 `gcp-standards`) — they change often.4838. **Supply-chain incidents** in the ecosystem (precedents in the catalogue: LiteLLM on484 PyPI, March 2026).485486**Declared gaps — do NOT fill in from memory**:487488- **Exact volume threshold at which pgvector stops being enough**: deliberately not pinned. It depends489 on dimensionality, quantisation, filter selectivity, RAM and target latency. **It is measured with490 the method of §2.2.**491- **Memory consumption formulas per index family**: not pinned. The ones in circulation omit the492 real overhead of the graph and the payload. Measure it over a sample.493- **Impact on recall of each quantisation method**: **not pinned.** The compression factors come494 from the vendor's documentation (verified); recall depends on your corpus and your model.495- **Quantisation in Milvus 3.x**: not verified in detail in this review (the major is from Jul 2026).496 Consult its documentation before pinning anything.497- **Default auth status of Chroma and LanceDB**: verified only indirectly (Chroma without498 auth in the standard startup, port 8000; embedded LanceDB exposes no service). **Confirm it in their499 documentation before deploying.**500- **Figures for instances exposed on the Internet**: the pattern is confirmed by public research501 (Orca Security, May 2026); **the specific counts circulating in blogs are not quoted as facts.**502- **Latencies, throughput and comparative benchmarks between engines**: not pinned. The public ones are almost503 always from vendors, without reproducible conditions and over academic datasets.504- **Prices of the managed services**: not pinned.505506If the web contradicts this document, **the web wins** — flag the discrepancy.