Skip to content

One filter language for every vector store

A unified TypeScript SDK for Qdrant, pgvector, Pinecone, Supabase, Upstash Vector, Cloudflare Vectorize, and Redis. Write one metadata filter and each adapter compiles it to the provider’s native syntax.

import { QdrantClient } from "@qdrant/js-client-rest";
import { and, eq, gt } from "vecstore-sdk";
import { createQdrantStore } from "vecstore-sdk/qdrant";

const store = createQdrantStore({
  client: new QdrantClient({ url }),
});

const result = await store.index("docs").query({
  vector,
  topK: 5,
  filter: and(
    eq("genre", "drama"),
    gt("year", 2000)
  ),
});
and(eq("genre", "drama"), gt("year", 2000))
{
  "must": [
    {
      "key": "genre",
      "match": { "value": "drama" }
    },
    {
      "key": "year",
      "range": { "gt": 2000 }
    }
  ]
}

See all supported providers

7
Providers
12
Filter builders
0
Runtime dependencies
MIT
License

The provider-agnostic vector toolkit

Vector databases agree on the verbs and disagree on everything else. VecStore SDK keeps the verbs and hides the rest, so switching providers changes one import and one config object.

  • Qdrant
  • pgvector
  • Pinecone
  • Supabase
  • Upstash
  • Vectorize
  • Redis

One filter, compiled natively.

Write and, or, not, eq, gt, isIn once. Each adapter emits the provider's native syntax.

Errors as values, never thrown.

Every call returns a Result. Match on the error kind instead of catching provider exceptions.

Namespaces on every provider.

Pinecone, Upstash, and Vectorize have them. Qdrant, pgvector, Supabase, and Redis get them emulated with the same API.

VecStore Core

Four record verbs, three index verbs, and a filter AST with twelve builders. The same signatures on every provider.

Adapters

Thin wrappers over the native client you already use. The raw client stays one property away.

Read the docs
switch-provider.ts
import { Pool } from "pg";
import { createPgvectorStore } from "vecstore-sdk/pgvector";

const store = createPgvectorStore({
  client: new Pool({ connectionString }),
});

const docs = store.index("docs", { namespace: "tenant_1" });

await docs.upsert([{ id: "doc-1", vector, metadata: { genre: "drama" } }]);

const result = await docs.query({ vector, topK: 5 });

if (!result.ok) {
  switch (result.error.kind) {
    case "not_found":
      return [];
    default:
      throw new Error(result.error.message);
  }
}
  • upsert()
  • query()
  • fetch()
  • delete()
  • createIndex()
  • deleteIndex()
  • listIndexes()
  • index()

Bring your own client

Provider SDKs are optional peer dependencies. Install only the one you use and the adapter imports nothing else.

See all seven providers

Qdrant

Wraps QdrantClient. Maps string ids to UUID point ids and emulates namespaces with a payload key.

pgvector

Wraps a pg Pool or Client. Compiles filters to JSONB predicates and stores namespaces in a column.

Pinecone

Wraps the Pinecone client. Uses native namespaces and metadata filters directly.

Cloudflare Vectorize

Drives the Vectorize v2 HTTP API. Uses native namespaces and reports what Vectorize has no call for.

Build with VecStoreSDKtoday

Get started with the docs, or open the repository and read the design notes.

Visit documentation