Convex vector store
The ConvexVector class provides vector storage and similarity search using Convex. It stores embeddings inside Convex and performs cosine similarity search in the Mastra adapter.
ConvexVector reads matching vectors through the Mastra storage handler, filters in JavaScript, computes cosine similarity, sorts results, and returns the top matches. Use it for local development, tests, and small datasets.
For production vector search on Convex, use ConvexNativeVector. It uses the Convex native vectorSearch API, which requires a deployed Convex vector index and a Convex action.
InstallationDirect link to Installation
- npm
- pnpm
- Yarn
- Bun
npm install @mastra/convex@latest
pnpm add @mastra/convex@latest
yarn add @mastra/convex@latest
bun add @mastra/convex@latest
Convex setupDirect link to Convex setup
Before using ConvexVector, you need to set up the Convex schema and storage handler. See Convex Storage Setup for setup instructions.
Constructor optionsDirect link to Constructor options
deploymentUrl:
adminAuthToken:
storageFunction?:
Constructor examplesDirect link to Constructor examples
Basic configurationDirect link to Basic configuration
import { ConvexVector } from '@mastra/convex'
const vectorStore = new ConvexVector({
id: 'convex-vectors',
deploymentUrl: 'https://your-project.convex.cloud',
adminAuthToken: 'your-admin-token',
})
Native Convex vector searchDirect link to Native Convex vector search
Use ConvexNativeVector for production vector workloads. It stores vectors in a dedicated Convex table and queries a schema-defined Convex vector index.
In convex/schema.ts, define a dedicated table for each Mastra vector index:
import { defineSchema } from 'convex/server'
import { defineMastraNativeVectorTable } from '@mastra/convex/schema'
export default defineSchema({
docs_vectors: defineMastraNativeVectorTable({
dimensions: 1536,
}),
})
In convex/mastra/nativeVector.ts, export the native vector handlers:
import {
mastraNativeVectorAction,
mastraNativeVectorMutation,
mastraNativeVectorQuery,
} from '@mastra/convex/server'
export const query = mastraNativeVectorAction
export const read = mastraNativeVectorQuery
export const write = mastraNativeVectorMutation
In your Mastra app, configure ConvexNativeVector with the deployed table and vector index:
import { ConvexNativeVector } from '@mastra/convex'
const vectorStore = new ConvexNativeVector({
id: 'convex-native-vectors',
deploymentUrl: process.env.CONVEX_URL!,
adminAuthToken: process.env.CONVEX_ADMIN_KEY!,
indexes: {
docs: {
tableName: 'docs_vectors',
vectorIndexName: 'by_embedding',
dimension: 1536,
},
},
})
const results = await vectorStore.query({
indexName: 'docs',
queryVector: embedding,
topK: 10,
})
For native filter support, declare filter fields in your Convex schema. The native vector handlers copy matching metadata fields to top-level document fields when vectors are written.
import { defineSchema, defineTable } from 'convex/server'
import { v } from 'convex/values'
export default defineSchema({
docs_vectors: defineTable({
id: v.string(),
embedding: v.array(v.float64()),
metadata: v.optional(v.any()),
tenantId: v.string(),
})
.index('by_record_id', ['id'])
.vectorIndex('by_embedding', {
vectorField: 'embedding',
dimensions: 1536,
filterFields: ['tenantId'],
}),
})
const vectorStore = new ConvexNativeVector({
id: 'convex-native-vectors',
deploymentUrl: process.env.CONVEX_URL!,
adminAuthToken: process.env.CONVEX_ADMIN_KEY!,
indexes: {
docs: {
tableName: 'docs_vectors',
dimension: 1536,
filterFields: ['tenantId'],
},
},
})
await vectorStore.upsert({
indexName: 'docs',
ids: ['chunk-1'],
vectors: [embedding],
metadata: [{ tenantId: 'acme', text: 'Account setup guide' }],
})
const results = await vectorStore.query({
indexName: 'docs',
queryVector: embedding,
filter: { tenantId: 'acme' },
})
ConvexNativeVector supports Convex native vector filter shapes: one equality field, or $or of equality fields. It doesn't support metadata-only queries, filter-based updates, or filter-based deletes. Use vector IDs for updates and deletes.
Custom storage functionDirect link to Custom storage function
const vectorStore = new ConvexVector({
id: 'convex-vectors',
deploymentUrl: 'https://your-project.convex.cloud',
adminAuthToken: 'your-admin-token',
storageFunction: 'custom/path:handler',
})
MethodsDirect link to Methods
createIndex()Direct link to createindex
indexName:
dimension:
metric?:
await vectorStore.createIndex({
indexName: 'my_vectors',
dimension: 1536,
})
upsert()Direct link to upsert
indexName:
vectors:
metadata?:
ids?:
await vectorStore.upsert({
indexName: "my_vectors",
vectors: [[0.1, 0.2, 0.3, ...]],
metadata: [{ label: "example" }],
ids: ["vec-1"],
});
query()Direct link to query
indexName:
queryVector:
topK?:
filter?:
includeVector?:
const results = await vectorStore.query({
indexName: "my_vectors",
queryVector: [0.1, 0.2, 0.3, ...],
topK: 5,
filter: { category: "documents" },
});
listIndexes()Direct link to listindexes
Returns an array of index names as strings.
const indexes = await vectorStore.listIndexes()
// ["my_vectors", "embeddings", ...]
describeIndex()Direct link to describeindex
indexName:
Returns:
interface IndexStats {
dimension: number
count: number
metric: 'cosine' | 'euclidean' | 'dotproduct'
}
deleteIndex()Direct link to deleteindex
indexName:
Deletes the index and all its vectors.
await vectorStore.deleteIndex({ indexName: 'my_vectors' })
updateVector()Direct link to updatevector
Update a single vector by ID or by metadata filter. Either id or filter must be provided, but not both.
indexName:
id?:
filter?:
update:
// Update by ID
await vectorStore.updateVector({
indexName: 'my_vectors',
id: 'vector123',
update: {
vector: [0.1, 0.2, 0.3],
metadata: { label: 'updated' },
},
})
// Update by filter
await vectorStore.updateVector({
indexName: 'my_vectors',
filter: { category: 'product' },
update: {
metadata: { status: 'reviewed' },
},
})
deleteVector()Direct link to deletevector
indexName:
id:
await vectorStore.deleteVector({ indexName: 'my_vectors', id: 'vector123' })
deleteVectors()Direct link to deletevectors
Delete multiple vectors by IDs or by metadata filter. Either ids or filter must be provided, but not both.
indexName:
ids?:
filter?:
// Delete by IDs
await vectorStore.deleteVectors({
indexName: 'my_vectors',
ids: ['vec1', 'vec2', 'vec3'],
})
// Delete by filter
await vectorStore.deleteVectors({
indexName: 'my_vectors',
filter: { status: 'archived' },
})
Response typesDirect link to Response types
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
}
Metadata filteringDirect link to Metadata filtering
ConvexVector supports metadata filtering with various operators. These filters are applied by the adapter after vectors are loaded from Convex.
// Simple equality
const results = await vectorStore.query({
indexName: 'my_vectors',
queryVector: embedding,
filter: { category: 'documents' },
})
// Comparison operators
const results = await vectorStore.query({
indexName: 'my_vectors',
queryVector: embedding,
filter: {
price: { $gt: 100 },
status: { $in: ['active', 'pending'] },
},
})
// Logical operators
const results = await vectorStore.query({
indexName: 'my_vectors',
queryVector: embedding,
filter: {
$and: [{ category: 'electronics' }, { price: { $lte: 500 } }],
},
})
Supported filter operatorsDirect link to Supported filter operators
| Operator | Description |
|---|---|
$eq | Equal to |
$ne | Not equal to |
$gt | Greater than |
$gte | Greater than or equal |
$lt | Less than |
$lte | Less than or equal |
$in | In array |
$nin | Not in array |
$and | Logical AND |
$or | Logical OR |
ArchitectureDirect link to Architecture
ConvexVector stores vectors in the mastra_vectors table with the following structure:
id: Unique vector identifierindexName: Name of the indexembedding: The vector data (array of floats)metadata: Optional JSON metadata
Vector similarity search is performed with cosine similarity in the Mastra adapter. This keeps setup flexible, but it's not designed for large production vector collections.
ConvexNativeVector stores each Mastra vector index in a dedicated Convex table. Its queries call a Convex action that uses ctx.vectorSearch, then load the matched documents through a Convex query. This follows the Convex native vector search model:
- Vector indexes are declared in
convex/schema.ts. - Vector search runs from a Convex action.
topKmust be between1and256.- Filters must target fields listed in the Convex vector index
filterFields. - Use one dedicated table per Mastra vector index to avoid cross-index results.
Use an external vector database when you need dynamic index creation at runtime, metadata-only queries, complex filter operators, filter-based bulk updates or deletes, or result limits above Convex's native vector search cap.