---
url: 'https://adk.nht.io/batteries/vector/adapters.md'
description: >-
  All 29 vector backends by architectural class, each with its per-backend
  caveats and TEST_VECTOR_* environment gating.
---

# The Adapter Matrix

## LLM summary — The Adapter Matrix

* 29 adapters, each at `@nhtio/adk/batteries/vector/<name>`. Two are cross-env and re-exported from the core barrel (`in_memory`, `orama`); the rest are Node-only deep-import-only so their optional-peer driver loads on demand.
* In-process / browser: `in_memory` (reference, no driver), `orama` (`@orama/orama`, cross-env), `hnswlib` (`hnswlib-node`, native), `lancedb` (`@lancedb/lancedb` + `apache-arrow`), `sqlite_vec` (`better-sqlite3` + `sqlite-vec`, ACID/transactions), `duckdb` (`@duckdb/node-api`, vss).
* SQL-extension: `pgvector` (`pg`, ACID/transactions), `mariadb` (`mariadb`, native VECTOR 11.7+), `oracle23ai` (`oracledb` thin; VECTOR rejected in SYSTEM tablespace — user needs a normal default tablespace), `clickhouse` (`@clickhouse/client`).
* Self-hosted server: `qdrant`, `weaviate`, `milvus`, `chroma`, `redis` (RediSearch; covers Valkey), `elasticsearch` (ES8 `dense_vector` + top-level knn; use the v8 client against an 8.x server), `opensearch` (OpenSearch `knn_vector`/query.knn dialect — distinct from elasticsearch), `solr`, `typesense`, `meilisearch`, `mongodb` (Atlas Vector Search), `surrealdb`, `neo4j`, `arangodb`, `couchbase` (Enterprise only for vector search), `vespa` (collection = doc type in a deployed application package).
* Managed / serverless: `pinecone` (eventual; needs index + key), `s3vectors` (AWS; cosine/euclidean only — no dot; topK max 100; dims region-bound), `cloudflare` (Vectorize V2; dims 32–1536; topK max 50 w/ values+metadata; aggressively eventual).
* Each adapter's integration suite is gated on a `TEST_VECTOR_<NAME>_URL` (or key/bucket) env var: set it to run that suite, leave it blank to skip (green, not red). `in_memory`/`orama` need no infra. sqlite-vec/duckdb take `:memory:`. Managed services need keys, no local container; they're omitted from the CI matrix.
* Backed out (NOT shipped, documented blockers): Kùzu (deprecated npm package), Memgraph (vector-index deletion bug), Vearch (arm64 image defect).
* Every shipped adapter passes the same `runVectorStoreConformance` 7/7 contract; caveats below are hard backend constraints, not behavioral differences in the builder contract.

29 adapters, one contract. Every one of them passes the same 7-test conformance suite, so the builder behaves identically across all of them — the entries below differ only in what their backend physically can and can't do (an edition requirement, a dimension floor, a metric it lacks, how lazily it becomes consistent). Each adapter lives at `@nhtio/adk/batteries/vector/<name>` and is reached by deep import, which is what loads its optional-peer driver. Two — `in_memory` and `orama` — are also re-exported from the core barrel because they run in the browser.

::: info How to read the caveats
A caveat is a fact about the backend, surfaced once so it doesn't ambush you in production. None of them change the query you write — `vs('docs').nearText(…).select('id').limit(10)` is the same line against all 29. They change what the backend requires to run, or what it can't promise. Where a backend is eventually consistent, see [Consistency & Capabilities](./consistency); where it has a metric or dimension limit, it's noted inline.
:::

## In-process & browser

No server. Embedded libraries, in-memory indexes, single-file stores — the cheapest path to a working store, and the only adapters that run in a browser tab.

| Adapter | Driver | Notes |
| --- | --- | --- |
| `in_memory` | none | The reference adapter. Hand-rolled cosine, cross-env, zero deps. The semantics every other adapter is tested against. Use for tests, prototypes, and the browser. |
| `orama` | `@orama/orama` | Cross-env, browser-capable. Real vector + hybrid store; backs in-browser retrieval (see [Ask ADK](../../showcase/ask-adk)). Re-exported from the core barrel. |
| `hnswlib` | `hnswlib-node` | Embedded ANN (HNSW), in-process, native addon. Fast approximate search with no server. |
| `lancedb` | `@lancedb/lancedb` + `apache-arrow` | Embedded columnar vector store; persists to disk, no server. |
| `sqlite_vec` | `better-sqlite3` + `sqlite-vec` | Single-file or `:memory:`. **ACID — `transactions: true`.** The cheapest real end-to-end backend. |
| `duckdb` | `@duckdb/node-api` | In-process via the `vss` extension; `:memory:` or a file. |

## SQL-extension

A real database you may already run, with a vector type or extension bolted on. Metadata is real columns; some offer true transactions.

| Adapter | Driver | Notes |
| --- | --- | --- |
| `pgvector` | `pg` | Postgres + the `vector` extension. **ACID — `transactions: true`.** Parameterized SQL filters, real columns, the works. |
| `mariadb` | `mariadb` | Native `VECTOR(N)` columns (MariaDB 11.7+); vectors via `VEC_FromText`/`VEC_ToText`. |
| `oracle23ai` | `oracledb` (thin mode, no Instant Client) | Native `VECTOR(dims, FLOAT32)`; KNN via `VECTOR_DISTANCE … FETCH APPROX FIRST k`. **Caveat: VECTOR columns are rejected in the SYSTEM tablespace** — the connecting user must default to a normal tablespace (e.g. `USERS`) with `CREATE TABLE`. |
| `clickhouse` | `@clickhouse/client` | Vector search over a MergeTree table; upsert is delete-then-insert (ClickHouse allows duplicate keys). |

## Self-hosted server

A dedicated vector engine (or a search/graph/document engine with vector search) you run yourself.

| Adapter | Driver | Notes |
| --- | --- | --- |
| `qdrant` | `@qdrant/js-client-rest` | Named vectors, native filter translation. |
| `weaviate` | `weaviate-client` | Named vectors; can embed server-side (`builtInEncoding`). |
| `milvus` | `@zilliz/milvus2-sdk-node` | Boolean-expression filters. |
| `chroma` | `chromadb` | Native `where` filtering. |
| `redis` | `redis` | RediSearch vector index. **Covers Valkey** — point it at a Valkey instance and it works unchanged. |
| `elasticsearch` | `@elastic/elasticsearch` | **ES 8 dialect** — `dense_vector` + a top-level `knn` clause. **Use the v8 client against an 8.x server** (a v9 client sends a compat header 8.x rejects). Distinct adapter from `opensearch`. |
| `opensearch` | `@opensearch-project/opensearch` | OpenSearch's `knn_vector` + `query.knn` dialect. A separate adapter because an ES client can't drive it and vice-versa. |
| `solr` | none (HTTP/JSON) | Dense-vector / kNN query parser (Solr 9+). The collection is a Solr core that must be precreated. |
| `typesense` | `typesense` | Native vector search. |
| `meilisearch` | `meilisearch` | Needs the vector-store experimental feature + a userProvided embedder. |
| `mongodb` | `mongodb` | Atlas Vector Search (`$vectorSearch`). The vector index is async; the document store is strongly consistent. |
| `surrealdb` | `surrealdb` | Multi-model; `vector::similarity::cosine` / `vector::distance::euclidean`. |
| `neo4j` | `neo4j-driver` | Native vector index (5.13+); `db.index.vector.queryNodes`. |
| `arangodb` | `arangojs` | Brute-force AQL `COSINE_SIMILARITY` / `L2_DISTANCE`. |
| `couchbase` | `couchbase` | **Enterprise Edition only** for vector search — Community rejects vector fields. Scope.collection = logical collection; scoped FTS vector index for KNN. |
| `vespa` | none (HTTP/JSON) | **A collection is a document type in a deployed application package** — the adapter rebuilds + redeploys the package (dependency-free store-zip) to the config server on create/drop. |

::: info Couchbase is Enterprise-only — and that's fine
Vector search in Couchbase requires the Enterprise edition; Community throws on vector fields. The adapter ships anyway. The kit provides batteries and does not enforce a backend's licensing — whether Couchbase EE fits your deployment is your call, not something the battery gates on.
:::

## Managed / serverless

Someone else runs the infrastructure. No local container; you supply credentials. These are eventually consistent (see [Consistency & Capabilities](./consistency)) and are omitted from the CI matrix — their suites run only when their credentials are set.

| Adapter | Driver | Notes |
| --- | --- | --- |
| `pinecone` | `@pinecone-database/pinecone` | Needs an existing index + API key. Eventually consistent (`configurable` consistency); a logical collection maps to a namespace. Can embed server-side. |
| `s3vectors` | `@aws-sdk/client-s3vectors` | AWS S3 Vectors. Bucket provisioned out-of-band; collection = an index in it. **cosine/euclidean only (no dot)**, **topK capped at 100**, index names 3–63 chars. |
| `cloudflare` | none (Vectorize V2 REST, pure `fetch`) | Cloudflare Vectorize. **Dimensions 32–1536**, **topK capped at 50** when returning values/metadata, aggressively eventually consistent. No driver dependency. |

## Running an adapter's integration suite

Every adapter's functional suite is gated on an environment variable — set it to run that suite against a live backend, leave it blank and the suite **skips green, not red**. The zero-infra ones run out of the box; the rest you point at a container or a service.

```bash
# zero infra — run as-is
TEST_VECTOR_ORAMA_URL=1            # orama, in-process
TEST_VECTOR_SQLITE_VEC_URL=:memory: # sqlite-vec, no server
TEST_VECTOR_DUCKDB_URL=:memory:     # duckdb, no server
TEST_VECTOR_HNSWLIB_URL=1           # hnswlib, embedded
TEST_VECTOR_LANCEDB_URL=1           # lancedb, embedded (temp dir per test)

# a local container (see docker-compose.vector.yml profiles)
TEST_VECTOR_PGVECTOR_URL=postgres://vector:vector@localhost:5432/vector
TEST_VECTOR_QDRANT_URL=http://localhost:6333
TEST_VECTOR_ELASTICSEARCH_URL=http://localhost:9200
# … one TEST_VECTOR_<NAME>_URL per backend

# a managed service — credentials, no container
TEST_VECTOR_PINECONE_API_KEY=…  TEST_VECTOR_PINECONE_INDEX=…
TEST_VECTOR_S3VECTORS_BUCKET=…  TEST_VECTOR_S3VECTORS_REGION=…
TEST_VECTOR_CLOUDFLARE_ACCOUNT_ID=…  TEST_VECTOR_CLOUDFLARE_API_KEY=…
```

The full list of variables (with the exact connection-string shapes and per-backend extras like `_USER`/`_PASS`/`_TOKEN`) lives in `.env.test.example`, and the container definitions are in `docker-compose.vector.yml` — one Compose profile per backend. The shipped adapters are each verified at **7/7 conformance, run deterministically**, against a live instance.

## What didn't ship

Three backends were attempted and backed out. They are not adapters you can import; they're recorded here so the gaps are intentional and documented, not mysterious:

| Backend | Why it's not here |
| --- | --- |
| **Kùzu** | The `kuzu` npm package is flagged "no longer supported"; the only alternative is stale and WASM-only. No viable non-deprecated Node distribution. |
| **Memgraph** | Backend defect: `vector_search.search` throws after a `DETACH DELETE` of an indexed node (a dangling index tombstone that drop+recreate doesn't prune), so the conformance suite's delete-then-read can't pass. Revisit when the index-deletion pruning is fixed. |
| **Vearch** | The published arm64 image is non-functional — its JSON serialization falls back to a broken path and every API call returns a 500. An image/architecture defect, not an adapter problem. |

## Where to go next

* [Consistency & Capabilities](./consistency) — the eventual-consistency story for the managed backends, and the `capabilities` flags per adapter.
* [Writing an Adapter](./custom-adapter) — add the 30th backend yourself.
* [The Query Builder & Filters](./query-builder) — the query that runs identically across all of these.
