# 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.4',
  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)