docs/src/content/en/reference/vectors/upstash.mdx
The UpstashVector class provides vector search using Upstash Vector, a serverless vector database service that provides vector similarity search with metadata filtering capabilities and hybrid search support.
<PropertiesTable content={[ { name: 'url', type: 'string', description: 'Upstash Vector database URL', }, { name: 'token', type: 'string', description: 'Upstash Vector API token', }, ]} />
createIndex()Note: This method is a no-op for Upstash as indexes are created automatically.
<PropertiesTable content={[ { name: 'indexName', type: 'string', description: 'Name of the index to create', }, { name: 'dimension', type: 'number', description: 'Vector dimension (must match your embedding model)', }, { name: 'metric', type: "'cosine' | 'euclidean' | 'dotproduct'", isOptional: true, defaultValue: 'cosine', description: 'Distance metric for similarity search', }, ]} />
upsert()<PropertiesTable content={[ { name: 'indexName', type: 'string', description: 'Name of the index to upsert into', }, { name: 'vectors', type: 'number[][]', description: 'Array of embedding vectors', }, { name: 'sparseVectors', type: '{ indices: number[], values: number[] }[]', isOptional: true, description: 'Array of sparse vectors for hybrid search. Each sparse vector must have matching indices and values arrays.', }, { name: 'metadata', type: 'Record<string, any>[]', isOptional: true, description: 'Metadata for each vector', }, { name: 'ids', type: 'string[]', isOptional: true, description: 'Optional vector IDs (auto-generated if not provided)', }, ]} />
query()<PropertiesTable content={[ { name: 'indexName', type: 'string', description: 'Name of the index to query', }, { name: 'queryVector', type: 'number[]', description: 'Query vector to find similar vectors', }, { name: 'sparseVector', type: '{ indices: number[], values: number[] }', isOptional: true, description: 'Optional sparse vector for hybrid search. Must have matching indices and values arrays.', }, { name: 'topK', type: 'number', isOptional: true, defaultValue: '10', description: 'Number of results to return', }, { name: 'filter', type: 'Record<string, any>', isOptional: true, description: 'Metadata filters for the query', }, { name: 'includeVector', type: 'boolean', isOptional: true, defaultValue: 'false', description: 'Whether to include vectors in the results', }, { name: 'fusionAlgorithm', type: 'FusionAlgorithm', isOptional: true, description: 'Algorithm used to combine dense and sparse search results in hybrid search (e.g., RRF - Reciprocal Rank Fusion)', }, { name: 'queryMode', type: 'QueryMode', isOptional: true, description: "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()<PropertiesTable content={[ { name: 'indexName', type: 'string', description: 'Name of the index to describe', }, ]} />
Returns:
interface IndexStats {
dimension: number
count: number
metric: 'cosine' | 'euclidean' | 'dotproduct'
}
deleteIndex()<PropertiesTable content={[ { name: 'indexName', type: 'string', description: 'Name of the index (namespace) to delete', }, ]} />
updateVector()<PropertiesTable content={[ { name: 'indexName', type: 'string', description: 'Name of the index to update', }, { name: 'id', type: 'string', description: 'ID of the item to update', }, { name: 'update', type: 'object', description: '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()<PropertiesTable content={[ { name: 'indexName', type: 'string', description: 'Name of the index from which to delete the item', }, { name: 'id', type: 'string', description: '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.
Upstash Vector supports hybrid search that combines semantic search (dense vectors) with keyword-based search (sparse vectors) for improved relevance and accuracy.
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,
})
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,
})
// 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' },
},
})
Query results are returned in this format:
interface QueryResult {
id: string
score: number
metadata: Record<string, any>
vector?: number[] // Only included if includeVector is true
}
The store throws typed errors that can be caught:
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
}
}
Required environment variables:
UPSTASH_VECTOR_URL: Your Upstash Vector database URLUPSTASH_VECTOR_TOKEN: Your Upstash Vector API tokenEmbeddings 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 install @mastra/fastembed@latest
Add the following to your agent:
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,
},
},
}),
})