Storing Vectors
Insert and update vector embeddings with metadata using the JavaScript SDK or Postgres.
This feature is in alpha
Expect rapid changes, limited features, and possible breaking updates. Share feedback as we refine the experience and expand access.
Once you've created a bucket and index, you can start storing vectors. Vectors can include optional metadata for filtering and enrichment during queries.
Basic vector insertion
import { } from '@supabase/supabase-js'const = ('https://your-project-id.supabase.co', 'your-service-key')// Get bucket and indexconst = ...('embeddings')const = .('documents-openai')// Insert vectorsconst { } = await .({ : [ { : 'doc-1', : { : [0.1, 0.2, 0.3 /* ... rest of embedding ... */], }, : { : 'Getting Started with Vector Buckets', : 'documentation', }, }, { : 'doc-2', : { : [0.4, 0.5, 0.6 /* ... rest of embedding ... */], }, : { : 'Advanced Vector Search', : 'blog', }, }, ],})if () { .('Error storing vectors:', )} else { .('✓ Vectors stored successfully')}from supabase import create_clientsupabase = create_client('https://your-project-id.supabase.co', 'your-service-key')# Get bucket and indexbucket = supabase.storage.vectors().from_('embeddings')index = bucket.index('documents-openai')# Insert vectorsindex.put([ { 'key': 'doc-1', 'data': {'float32': [0.1, 0.2, 0.3]}, # ... rest of embedding 'metadata': { 'title': 'Getting Started with Vector Buckets', 'source': 'documentation', }, }, { 'key': 'doc-2', 'data': {'float32': [0.4, 0.5, 0.6]}, # ... rest of embedding 'metadata': { 'title': 'Advanced Vector Search', 'source': 'blog', }, },])print('✓ Vectors stored successfully')-- Setup S3 Vector Wrapper (one-time setup)-- https://supabase.com/docs/guides/database/extensions/wrappers/s3_vectors-- Insert vectors into the indexINSERT INTO s3_vectors.documents_openai (key, data, metadata)VALUES ( 'doc-1', '[0.1, 0.2, 0.3, /* ... rest of embedding ... */]'::embd, '{"title": "Getting Started with Vector Buckets", "source": "documentation"}'::jsonb ), ( 'doc-2', '[0.4, 0.5, 0.6, /* ... rest of embedding ... */]'::embd, '{"title": "Advanced Vector Search", "source": "blog"}'::jsonb );Storing vectors from Embeddings API
Generate embeddings using an LLM API and store them directly:
import { createClient } from '@supabase/supabase-js'import OpenAI from 'openai'const supabase = createClient('https://your-project-id.supabase.co', 'your-service-key')const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY,})// Documents to embed and storeconst documents = [ { id: '1', title: 'How to Train Your AI', content: 'Guide for training models...' }, { id: '2', title: 'Vector Search Best Practices', content: 'Tips for semantic search...' }, { id: '3', title: 'Building RAG Systems', content: 'Implementing retrieval-augmented generation...', },]// Generate embeddingsconst embeddings = await openai.embeddings.create({ model: 'text-embedding-3-small', input: documents.map((doc) => doc.content),})// Prepare vectors for storageconst vectors = documents.map((doc, index) => ({ key: doc.id, data: { float32: embeddings.data[index].embedding, }, metadata: { title: doc.title, source: 'knowledge_base', created_at: new Date().toISOString(), },}))// Store vectors in batches (max 500 per request)const bucket = supabase.storage.vectors.from('embeddings')const vectorIndex = bucket.index('documents-openai')for (let i = 0; i < vectors.length; i += 500) { const batch = vectors.slice(i, i + 500) const { error } = await vectorIndex.putVectors({ vectors: batch }) if (error) { console.error(`Error storing batch ${i / 500 + 1}:`, error) } else { console.log(`✓ Stored batch ${i / 500 + 1} (${batch.length} vectors)`) }}from supabase import create_clientfrom openai import OpenAIfrom datetime import datetimesupabase = create_client('https://your-project-id.supabase.co', 'your-service-key')openai = OpenAI(api_key=os.environ.get('OPENAI_API_KEY'))# Documents to embed and storedocuments = [ {'id': '1', 'title': 'How to Train Your AI', 'content': 'Guide for training models...'}, {'id': '2', 'title': 'Vector Search Best Practices', 'content': 'Tips for semantic search...'}, {'id': '3', 'title': 'Building RAG Systems', 'content': 'Implementing retrieval-augmented generation...'},]# Generate embeddingsembeddings_response = openai.embeddings.create( model='text-embedding-3-small', input=[doc['content'] for doc in documents])# Prepare vectors for storagevectors = []for doc, embedding_data in zip(documents, embeddings_response.data): vectors.append({ 'key': doc['id'], 'data': {'float32': embedding_data.embedding}, 'metadata': { 'title': doc['title'], 'source': 'knowledge_base', 'created_at': datetime.now().isoformat(), }, })# Store vectors in batches (max 500 per request)bucket = supabase.storage.vectors().from_('embeddings')vector_index = bucket.index('documents-openai')batch_size = 500for i in range(0, len(vectors), batch_size): batch = vectors[i:i + batch_size] vector_index.put(batch) print(f'✓ Stored batch {i // batch_size + 1} ({len(batch)} vectors)')-- Insert vectors with pre-generated embeddingsINSERT INTO s3_vectors.documents_openai (key, data, metadata)VALUES ( '1', '[0.1, 0.2, 0.3, /* ... rest of embedding ... */]'::embd, '{"title": "How to Train Your AI", "source": "knowledge_base", "created_at": "2025-01-01T00:00:00Z"}'::jsonb ), ( '2', '[0.4, 0.5, 0.6, /* ... rest of embedding ... */]'::embd, '{"title": "Vector Search Best Practices", "source": "knowledge_base", "created_at": "2025-01-01T00:00:00Z"}'::jsonb ), ( '3', '[0.7, 0.8, 0.9, /* ... rest of embedding ... */]'::embd, '{"title": "Building RAG Systems", "source": "knowledge_base", "created_at": "2025-01-01T00:00:00Z"}'::jsonb );Updating vectors
const index = bucket.index('documents-openai')// Update a vector (same key)const { error } = await index.putVectors({ vectors: [ { key: 'doc-1', data: { float32: [0.15, 0.25, 0.35 /* ... updated embedding ... */], }, metadata: { title: 'Getting Started with Vector Buckets - Updated', updated_at: new Date().toISOString(), }, }, ],})if (!error) { console.log('✓ Vector updated successfully')}index = bucket.index('documents-openai')# Update a vector (same key)index.put([ { 'key': 'doc-1', 'data': {'float32': [0.15, 0.25, 0.35]}, # ... updated embedding 'metadata': { 'title': 'Getting Started with Vector Buckets - Updated', 'updated_at': datetime.now().isoformat(), }, },])print('✓ Vector updated successfully')-- Update a vector (delete and re-insert)DELETE FROM s3_vectors.documents_openai WHERE key = 'doc-1';INSERT INTO s3_vectors.documents_openai (key, data, metadata)VALUES ( 'doc-1', '[0.15, 0.25, 0.35, /* ... updated embedding ... */]'::embd, '{"title": "Getting Started with Vector Buckets - Updated", "updated_at": "2025-01-01T00:00:00Z"}'::jsonb);Deleting vectors
const index = bucket.index('documents-openai')// Delete specific vectorsconst { error } = await index.deleteVectors({ keys: ['doc-1', 'doc-2'],})if (!error) { console.log('✓ Vectors deleted successfully')}index = bucket.index('documents-openai')# Delete specific vectorsindex.delete(['doc-1', 'doc-2'])print('✓ Vectors deleted successfully')-- Delete vectors by keydelete from s3_vectors.documents_openaiwhere key in ('doc-1', 'doc-2');Metadata best practices
Metadata makes vectors more useful by enabling filtering and context:
const vectors = [ { key: 'product-001', data: { float32: [...] }, metadata: { product_id: 'prod-001', category: 'electronics', price: 299.99, in_stock: true, tags: ['laptop', 'portable'], description: 'High-performance ultrabook' } }, { key: 'product-002', data: { float32: [...] }, metadata: { product_id: 'prod-002', category: 'electronics', price: 99.99, in_stock: true, tags: ['headphones', 'wireless'], description: 'Noise-cancelling wireless headphones' } }]const { error } = await index.putVectors({ vectors })Metadata field guidelines
- Keep it lightweight - Metadata is returned with query results, so large values increase response size
- Use consistent types - Store the same field with consistent data types across vectors
- Index key fields - Mark fields you'll filter by to improve query performance
- Avoid nested objects - While supported, flat structures are easier to filter
Batch processing large datasets
For storing large numbers of vectors efficiently:
import { createClient } from '@supabase/supabase-js'import fs from 'fs'const supabase = createClient(...)const index = supabase.storage.vectors .from('embeddings') .index('documents-openai')// Read embeddings from fileconst embeddingsFile = fs.readFileSync('embeddings.jsonl', 'utf-8')const lines = embeddingsFile.split('\n').filter(line => line.trim())const vectors = lines.map((line, idx) => { const { key, embedding, metadata } = JSON.parse(line) return { key, data: { float32: embedding }, metadata }})// Process in batchesconst BATCH_SIZE = 500let processed = 0for (let i = 0; i < vectors.length; i += BATCH_SIZE) { const batch = vectors.slice(i, i + BATCH_SIZE) try { const { error } = await index.putVectors({ vectors: batch }) if (error) throw error processed += batch.length console.log(`Progress: ${processed}/${vectors.length}`) } catch (error) { console.error(`Batch failed at offset ${i}:`, error) // Optionally implement retry logic }}console.log('✓ All vectors stored successfully')from supabase import create_clientimport jsonsupabase = create_client(...)index = supabase.storage.vectors().from_('embeddings').index('documents-openai')# Read embeddings from filewith open('embeddings.jsonl', 'r') as f: lines = [line.strip() for line in f if line.strip()]vectors = []for line in lines: data = json.loads(line) vectors.append({ 'key': data['key'], 'data': {'float32': data['embedding']}, 'metadata': data.get('metadata', {}) })# Process in batchesBATCH_SIZE = 500processed = 0for i in range(0, len(vectors), BATCH_SIZE): batch = vectors[i:i + BATCH_SIZE] try: index.put(batch) processed += len(batch) print(f'Progress: {processed}/{len(vectors)}') except Exception as e: print(f'Batch failed at offset {i}: {e}') # Optionally implement retry logicprint('✓ All vectors stored successfully')Performance optimization
Batch operations
Always use batch operations for better performance:
// ❌ Inefficient - Multiple requestsfor (const vector of vectors) { await index.putVectors({ vectors: [vector] })}// ✅ Efficient - Single batch operationawait index.putVectors({ vectors })# ❌ Inefficient - Multiple requestsfor vector in vectors: index.put([vector])# ✅ Efficient - Single batch operationindex.put(vectors)Metadata considerations
Keep metadata concise:
// ❌ Large metadatametadata: { full_document_text: 'Very long document content...', detailed_analysis: { /* large object */ }}// ✅ Lean metadatametadata: { doc_id: 'doc-123', category: 'news', summary: 'Brief summary'}