# Upstash Vector Store

The UpstashVector class provides vector search using [Upstash Vector](https://upstash.com/vector), a serverless vector database service that provides vector similarity search with metadata filtering capabilities and hybrid search support.

## Constructor Options

**url:** (`string`): Upstash Vector database URL

**token:** (`string`): Upstash Vector API token

## Methods

### createIndex()

Note: This method is a no-op for Upstash as indexes are created automatically.

**indexName:** (`string`): Name of the index to create

**dimension:** (`number`): Vector dimension (must match your embedding model)

**metric?:** (`'cosine' | 'euclidean' | 'dotproduct'`): Distance metric for similarity search (Default: `cosine`)

### upsert()

**indexName:** (`string`): Name of the index to upsert into

**vectors:** (`number[][]`): Array of embedding vectors

**sparseVectors?:** (`{ indices: number[], values: number[] }[]`): Array of sparse vectors for hybrid search. Each sparse vector must have matching indices and values arrays.

**metadata?:** (`Record<string, any>[]`): Metadata for each vector

**ids?:** (`string[]`): Optional vector IDs (auto-generated if not provided)

### query()

**indexName:** (`string`): Name of the index to query

**queryVector:** (`number[]`): Query vector to find similar vectors

**sparseVector?:** (`{ indices: number[], values: number[] }`): Optional sparse vector for hybrid search. Must have matching indices and values arrays.

**topK?:** (`number`): Number of results to return (Default: `10`)

**filter?:** (`Record<string, any>`): Metadata filters for the query

**includeVector?:** (`boolean`): Whether to include vectors in the results (Default: `false`)

**fusionAlgorithm?:** (`FusionAlgorithm`): Algorithm used to combine dense and sparse search results in hybrid search (e.g., RRF - Reciprocal Rank Fusion)

**queryMode?:** (`QueryMode`): Search mode: 'DENSE' for dense-only, 'SPARSE' for sparse-only, or 'HYBRID' for combined search

### listIndexes()

Returns an array of index names (namespaces) as strings.

### describeIndex()

**indexName:** (`string`): Name of the index to describe

Returns:

```typescript
interface IndexStats {
  dimension: number;
  count: number;
  metric: "cosine" | "euclidean" | "dotproduct";
}
```

### deleteIndex()

**indexName:** (`string`): Name of the index (namespace) to delete

### updateVector()

**indexName:** (`string`): Name of the index to update

**id:** (`string`): ID of the item to update

**update:** (`object`): Update object containing vector, sparse vector, and/or metadata

The `update` object can have the following properties:

- `vector` (optional): An array of numbers representing the new dense vector.
- `sparseVector` (optional): A sparse vector object with `indices` and `values` arrays for hybrid indexes.
- `metadata` (optional): A record of key-value pairs for metadata.

### deleteVector()

**indexName:** (`string`): Name of the index from which to delete the item

**id:** (`string`): ID of the item to delete

Attempts to delete an item by its ID from the specified index. Logs an error message if the deletion fails.

## Hybrid Vector Search

Upstash Vector supports hybrid search that combines semantic search (dense vectors) with keyword-based search (sparse vectors) for improved relevance and accuracy.

### Basic Hybrid Usage

```typescript
import { UpstashVector } from "@mastra/upstash";

const vectorStore = new UpstashVector({
  id: 'upstash-vector',
  url: process.env.UPSTASH_VECTOR_URL,
  token: process.env.UPSTASH_VECTOR_TOKEN,
});

// Upsert vectors with both dense and sparse components
const denseVectors = [
  [0.1, 0.2, 0.3],
  [0.4, 0.5, 0.6],
];
const sparseVectors = [
  { indices: [1, 5, 10], values: [0.8, 0.6, 0.4] },
  { indices: [2, 6, 11], values: [0.7, 0.5, 0.3] },
];

await vectorStore.upsert({
  indexName: "hybrid-index",
  vectors: denseVectors,
  sparseVectors: sparseVectors,
  metadata: [{ title: "Document 1" }, { title: "Document 2" }],
});

// Query with hybrid search
const results = await vectorStore.query({
  indexName: "hybrid-index",
  queryVector: [0.1, 0.2, 0.3],
  sparseVector: { indices: [1, 5], values: [0.9, 0.7] },
  topK: 10,
});
```

### Advanced Hybrid Search Options

```typescript
import { FusionAlgorithm, QueryMode } from "@upstash/vector";

// Query with specific fusion algorithm
const fusionResults = await vectorStore.query({
  indexName: "hybrid-index",
  queryVector: [0.1, 0.2, 0.3],
  sparseVector: { indices: [1, 5], values: [0.9, 0.7] },
  fusionAlgorithm: FusionAlgorithm.RRF,
  topK: 10,
});

// Dense-only search
const denseResults = await vectorStore.query({
  indexName: "hybrid-index",
  queryVector: [0.1, 0.2, 0.3],
  queryMode: QueryMode.DENSE,
  topK: 10,
});

// Sparse-only search
const sparseResults = await vectorStore.query({
  indexName: "hybrid-index",
  queryVector: [0.1, 0.2, 0.3], // Still required for index structure
  sparseVector: { indices: [1, 5], values: [0.9, 0.7] },
  queryMode: QueryMode.SPARSE,
  topK: 10,
});
```

### Updating Hybrid Vectors

```typescript
// Update both dense and sparse components
await vectorStore.updateVector({
  indexName: "hybrid-index",
  id: "vector-id",
  update: {
    vector: [0.2, 0.3, 0.4],
    sparseVector: { indices: [2, 7, 12], values: [0.9, 0.8, 0.6] },
    metadata: { title: "Updated Document" },
  },
});
```

## Response Types

Query results are returned in this format:

```typescript
interface QueryResult {
  id: string;
  score: number;
  metadata: Record<string, any>;
  vector?: number[]; // Only included if includeVector is true
}
```

## Error Handling

The store throws typed errors that can be caught:

```typescript
try {
  await store.query({
    indexName: "index_name",
    queryVector: queryVector,
  });
} catch (error) {
  if (error instanceof VectorStoreError) {
    console.log(error.code); // 'connection_failed' | 'invalid_dimension' | etc
    console.log(error.details); // Additional error context
  }
}
```

## Environment Variables

Required environment variables:

- `UPSTASH_VECTOR_URL`: Your Upstash Vector database URL
- `UPSTASH_VECTOR_TOKEN`: Your Upstash Vector API token

## Usage Example

### Local embeddings with fastembed

Embeddings are numeric vectors used by memory's `semanticRecall` to retrieve related messages by meaning (not keywords). This setup uses `@mastra/fastembed` to generate vector embeddings.

Install `fastembed` to get started:

**npm**:

```bash
npm install @mastra/fastembed@latest
```

**pnpm**:

```bash
pnpm add @mastra/fastembed@latest
```

**Yarn**:

```bash
yarn add @mastra/fastembed@latest
```

**Bun**:

```bash
bun add @mastra/fastembed@latest
```

Add the following to your agent:

```typescript
import { Memory } from "@mastra/memory";
import { Agent } from "@mastra/core/agent";
import { UpstashStore, UpstashVector } from "@mastra/upstash";
import { fastembed } from "@mastra/fastembed";

export const upstashAgent = new Agent({
  id: "upstash-agent",
  name: "Upstash Agent",
  instructions:
    "You are an AI agent with the ability to automatically recall memories from previous interactions.",
  model: "openai/gpt-5.1",
  memory: new Memory({
    storage: new UpstashStore({
      id: 'upstash-agent-storage',
      url: process.env.UPSTASH_REDIS_REST_URL!,
      token: process.env.UPSTASH_REDIS_REST_TOKEN!,
    }),
    vector: new UpstashVector({
      id: 'upstash-agent-vector',
      url: process.env.UPSTASH_VECTOR_REST_URL!,
      token: process.env.UPSTASH_VECTOR_REST_TOKEN!,
    }),
    embedder: fastembed,
    options: {
      lastMessages: 10,
      semanticRecall: {
        topK: 3,
        messageRange: 2,
      },
    },
  }),
});
```

## Related

- [Metadata Filters](https://mastra.ai/reference/rag/metadata-filters)