Querying Vectors
Perform similarity search and retrieve vectors using JavaScript SDK or PostgreSQL.
This feature is in alpha
Expect rapid changes, limited features, and possible breaking updates. Share feedback as we refine the experience and expand access.
Vector similarity search finds vectors most similar to a query vector using distance metrics. You can query vectors using the JavaScript SDK or directly from Postgres using SQL.
Basic similarity search
12345678910111213141516171819202122232425import { createClient } from '@supabase/supabase-js'const supabase = createClient('https://your-project.supabase.co', 'your-service-key')const index = supabase.storage.vectors.from('embeddings').index('documents-openai')// Query with a vector embeddingconst { data, error } = await index.queryVectors({ queryVector: { float32: [0.1, 0.2, 0.3 /* ... embedding of 1536 dimensions ... */], }, topK: 5, returnDistance: true, returnMetadata: true,})if (error) { console.error('Query failed:', error)} else { // Results are ranked by similarity (lowest distance = most similar) data.vectors.forEach((result, rank) => { console.log(`${rank + 1}. ${result.metadata?.title}`) console.log(` Similarity score: ${result.distance.toFixed(4)}`) })}Semantic search
Find documents similar to a query by embedding the query text:
12345678910111213141516171819202122232425262728293031323334353637383940414243import { createClient } from '@supabase/supabase-js'import OpenAI from 'openai'const supabase = createClient(...)const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })async function semanticSearch(query, topK = 5) { // Embed the query const queryEmbedding = await openai.embeddings.create({ model: 'text-embedding-3-small', input: query }) const queryVector = queryEmbedding.data[0].embedding // Search for similar vectors const { data, error } = await supabase.storage.vectors .from('embeddings') .index('documents-openai') .queryVectors({ queryVector: { float32: queryVector }, topK, returnDistance: true, returnMetadata: true }) if (error) { throw error } return data.vectors.map((result) => ({ id: result.key, title: result.metadata?.title, similarity: 1 - result.distance, // Convert distance to similarity (0-1) metadata: result.metadata }))}// Usageconst results = await semanticSearch('How do I use vector search?')results.forEach((result) => { console.log(`${result.title} (${(result.similarity * 100).toFixed(1)}% similar)`)})Filtered similarity search
1234567891011121314151617const index = supabase.storage.vectors .from('embeddings') .index('documents-openai')// Search with metadata filterconst { data } = await index.queryVectors({ queryVector: { float32: [...embedding...] }, topK: 10, filter: { // Filter by metadata fields category: 'electronics', in_stock: true, price: { $lte: 500 } // Less than or equal to 500 }, returnDistance: true, returnMetadata: true})Retrieving specific vectors
12345678910111213const index = supabase.storage.vectors.from('embeddings').index('documents-openai')const { data, error } = await index.getVectors({ keys: ['doc-1', 'doc-2', 'doc-3'], returnData: true, returnMetadata: true,})if (!error) { data.vectors.forEach((vector) => { console.log(`${vector.key}: ${vector.metadata?.title}`) })}Listing vectors
123456789101112131415161718192021222324const index = supabase.storage.vectors.from('embeddings').index('documents-openai')let nextToken = undefinedlet pageCount = 0do { const { data, error } = await index.listVectors({ maxResults: 100, nextToken, returnData: false, // Don't return embeddings for faster response returnMetadata: true, }) if (error) break pageCount++ console.log(`Page ${pageCount}: ${data.vectors.length} vectors`) data.vectors.forEach((vector) => { console.log(` - ${vector.key}: ${vector.metadata?.title}`) }) nextToken = data.nextToken} while (nextToken)Hybrid search: Vectors + relational data
Combine similarity search with SQL filtering and joins:
123456789101112131415161718192021222324252627282930async function hybridSearch(queryVector, filters) { const index = supabase.storage.vectors.from('embeddings').index('documents-openai') // Get similar vectors with filters const { data: vectorResults } = await index.queryVectors({ queryVector: { float32: queryVector }, topK: 100, filter: filters, returnDistance: true, returnMetadata: true, }) // Get additional details from relational database const { data: details } = await supabase .from('documents') .select('*') .in( 'id', vectorResults.vectors.map((v) => v.metadata?.doc_id) ) // Merge results return vectorResults.vectors.map((vector) => { const detail = details?.find((d) => d.id === vector.metadata?.doc_id) return { ...vector, ...detail, } })}Real-world examples
RAG (retrieval-augmented generation)
1234567891011121314151617181920212223242526272829303132333435363738394041424344import OpenAI from 'openai'import { createClient } from '@supabase/supabase-js'async function retrieveContextForLLM(userQuery) { const supabase = createClient(...) const openai = new OpenAI() // 1. Embed the user query const queryEmbedding = await openai.embeddings.create({ model: 'text-embedding-3-small', input: userQuery }) // 2. Retrieve relevant documents const { data: vectorResults } = await supabase.storage.vectors .from('embeddings') .index('documents-openai') .queryVectors({ queryVector: { float32: queryEmbedding.data[0].embedding }, topK: 5, returnMetadata: true }) // 3. Use vectors to augment LLM prompt const context = vectorResults.vectors .map(v => v.metadata?.content || '') .join('\n\n') const response = await openai.chat.completions.create({ model: 'gpt-4', messages: [ { role: 'system', content: `Use the following context to answer the user's question:\n\n${context}` }, { role: 'user', content: userQuery } ] }) return response.choices[0].message.content}Product recommendations
1234567891011121314151617181920212223async function recommendProducts(userEmbedding, topK = 5) { const supabase = createClient(...) // Find similar products const { data } = await supabase.storage.vectors .from('embeddings') .index('products-openai') .queryVectors({ queryVector: { float32: userEmbedding }, topK, filter: { in_stock: true }, returnMetadata: true }) return data.vectors.map((result) => ({ id: result.metadata?.product_id, name: result.metadata?.name, price: result.metadata?.price, similarity: 1 - result.distance }))}Filtering before similarity search
12345678// Use metadata filters to reduce search scopeconst { data } = await index.queryVectors({ queryVector, topK: 100, filter: { category: 'electronics', // Pre-filter by category },})