Working with Vector Indexes
Create, manage, and optimize vector indexes for efficient similarity search.
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 indexes organize embeddings within a bucket with consistent dimensions and distance metrics. Each index defines how similarity searches are performed across your vectors.
Understanding vector indexes
An index specifies:
- Index Name - Unique identifier within the bucket
- Dimension - Size of vector embeddings (e.g., 1536 for OpenAI)
- Distance Metric - Similarity calculation method (cosine, euclidean, or L2)
- Data Type - Vector format (currently
float32)
Think of an index as a table in a traditional database. It has a schema (dimension) and a query strategy (distance metric).
Creating indexes
Via Dashboard
- Open your vector bucket in the Supabase Dashboard.
- Click Create Index.
- Enter an index name (e.g.,
documents-openai). - Set the dimension matching your embeddings (e.g.,
1536for OpenAI's text-embedding-3-small). - Select the distance metric (
cosine,euclidean, orl2). - Click Create.
Via SDK
import { } from '@supabase/supabase-js'const = ('https://your-project-id.supabase.co', 'your-service-key')const = ...('embeddings')// Create an indexconst { , } = await .({ : 'documents-openai', : 'float32', : 1536, : 'cosine',})if () { .('Error creating index:', )} else { .('Index created:', )}from supabase import create_clientsupabase = create_client('https://your-project-id.supabase.co', 'your-service-key')bucket = supabase.storage.vectors().from_('embeddings')# Create an indexbucket.create_index( index_name='documents-openai', dimension=1536, distance_metric='cosine', data_type='float32')print('✓ Index created: documents-openai')Choosing the right metric
Most modern embedding models work best with cosine distance:
- OpenAI (text-embedding-3-small, text-embedding-3-large): Cosine
- Cohere (embed-english-v3.0): Cosine
- Hugging Face (sentence-transformers): Cosine
- Google (text-embedding-004): Cosine
- Llama 2 embeddings: Cosine or L2
Tip: Check your embedding model's documentation for the recommended distance metric.
Important: Creating an index with incorrect dimensions will cause insert and query operations to fail.
Managing multiple indexes
Create multiple indexes for different use cases or embedding models:
const bucket = supabase.storage.vectors.from('embeddings')// Index for OpenAI embeddingsawait bucket.createIndex({ indexName: 'documents-openai', dimension: 1536, distanceMetric: 'cosine', dataType: 'float32',})// Index for Cohere embeddingsawait bucket.createIndex({ indexName: 'documents-cohere', dimension: 1024, distanceMetric: 'cosine', dataType: 'float32',})// Index for different use caseawait bucket.createIndex({ indexName: 'images-openai', dimension: 1536, distanceMetric: 'cosine', dataType: 'float32',})// List all indexesconst { data: indexes } = await bucket.listIndexes()console.log('All indexes:', indexes)bucket = supabase.storage.vectors().from_('embeddings')# Index for OpenAI embeddingsbucket.create_index( index_name='documents-openai', dimension=1536, distance_metric='cosine', data_type='float32')# Index for Cohere embeddingsbucket.create_index( index_name='documents-cohere', dimension=1024, distance_metric='cosine', data_type='float32')# Index for different use casebucket.create_index( index_name='images-openai', dimension=1536, distance_metric='cosine', data_type='float32')# List all indexesindexes = bucket.list_indexes()print('All indexes:', indexes)Use cases for multiple indexes
- Different embedding models - Store vectors from OpenAI, Cohere, and local models separately
- Different domains - Maintain separate indexes for documents, images, products, etc.
- A/B testing - Compare different embedding models side-by-side
- Multi-language - Keep language-specific embeddings separate
Listing and inspecting indexes
List all indexes in a bucket
const bucket = supabase.storage.vectors.from('embeddings')const { data: indexes, error } = await bucket.listIndexes()if (!error) { indexes?.forEach((index) => { console.log(`Index: ${index.name}`) console.log(` Dimension: ${index.dimension}`) console.log(` Distance: ${index.distanceMetric}`) })}bucket = supabase.storage.vectors().from_('embeddings')indexes = bucket.list_indexes()if indexes: for index in indexes.indexes: print(f'Index: {index.indexName}')Get index details
const { data: indexDetails, error } = await bucket.getIndex('documents-openai')if (!error && indexDetails) { console.log(`Index: ${indexDetails.name}`) console.log(`Created at: ${indexDetails.createdAt}`) console.log(`Dimension: ${indexDetails.dimension}`) console.log(`Distance metric: ${indexDetails.distanceMetric}`)}index_details = bucket.get_index('documents-openai')if index_details: print(f'Index: {index_details.index.index_name}') print(f'Dimension: {index_details.index.dimension}') print(f'Distance metric: {index_details.index.distance_metric}')Deleting indexes
Delete an index to free storage space:
const bucket = supabase.storage.vectors.from('embeddings')const { error } = await bucket.deleteIndex('documents-openai')if (error) { console.error('Error deleting index:', error)} else { console.log('Index deleted successfully')}bucket = supabase.storage.vectors().from_('embeddings')bucket.delete_index('documents-openai')print('✓ Index deleted successfully')Before deleting an index
Warning: Deleting an index is permanent and cannot be undone.
- Backup important data - Export vectors before deletion if needed
- Update applications - Ensure no code references the deleted index
- Check dependencies - Verify no active queries use the index
- Plan the deletion - Do this during low-traffic periods
Immutable properties
Once created, these properties cannot be changed:
- Dimension - Must create new index with different dimension
- Distance metric - Cannot change after creation
- Data type - Currently only
float32supported
Optimizing index performance
// Good - Appropriate batch sizeconst batch = vectors.slice(0, 250)await index.putVectors({ vectors: batch })// Good - Filter metadata before queryconst { data } = await index.queryVectors({ queryVector, topK: 5, filter: { category: 'electronics' },})// Avoid - Single vector insertsfor (const vector of vectors) { await index.putVectors({ vectors: [vector] })}// Avoid - Returning unnecessary dataconst { data } = await index.queryVectors({ queryVector, topK: 1000, // Too many results returnData: true, // Include large embeddings})# Good - Appropriate batch sizebatch = vectors[:250]index.put(batch)# Good - Filter metadata before queryresults = index.query( query_vector=query_vector, topK=5, filter={'category': 'electronics'})# Avoid - Single vector insertsfor vector in vectors: index.put([vector])# Avoid - Returning unnecessary dataresults = index.query( query_vector=query_vector, topK=1000, # Too many results return_data=True # Include large embeddings)