# 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[]`): 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`): 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; 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)