Dashboard

Vectors (pgvector)

Store embeddings in Postgres with pgvector and run similarity search via RPC — the same model as Supabase Vector.

Bring your own embeddings

Voltbase stores and queries vectors. Generate embeddings with OpenAI, Hugging Face, or any model — dimensions must match the column (default 1536).

1. Enable pgvector

The vector extension is enabled automatically on new projects. Confirm under dashboard Extensions, or run:

enable.sql
create extension if not exists vector;

2. Vector columns

In the table editor pick type vector and set dimensions, or SQL:

schema.sql
create table documents (
  id uuid primary key default gen_random_uuid(),
  content text not null,
  embedding vector(1536),
  user_id uuid,
  created_at timestamptz not null default now()
);

3. Insert embeddings

Pass a number[] from the SDK — Voltbase casts it to vector:

insert.ts
import { createClient } from 'voltbase-js';

const voltbase = createClient(projectUrl, anonKey);

// embedding = await openai.embeddings.create(...).data[0].embedding
const embedding: number[] = /* length 1536 */;

const { data, error } = await voltbase.from('documents').insert({
  content: 'How do I reset my password?',
  embedding,
});

4. HNSW index

From the table Indexes tab choose method hnsw and ops vector_cosine_ops, or:

index.sql
create index documents_embedding_hnsw
  on documents
  using hnsw (embedding vector_cosine_ops);

5. match_* + rpc()

Like Supabase JS, similarity operators are exposed through a SQL function and rpc():

match_documents.sql
create or replace function match_documents(
  query_embedding vector(1536),
  match_threshold float default 0.7,
  match_count int default 10
)
returns table (
  id uuid,
  content text,
  similarity float
)
language sql
stable
as $$
  select
    documents.id,
    documents.content,
    1 - (documents.embedding <=> query_embedding) as similarity
  from documents
  where 1 - (documents.embedding <=> query_embedding) > match_threshold
  order by documents.embedding <=> query_embedding
  limit match_count;
$$;
search.ts
const { data, error } = await voltbase.rpc('match_documents', {
  query_embedding: queryVec,
  match_threshold: 0.78,
  match_count: 10,
});

6. RLS & grants

Keep functions as SECURITY INVOKER (default) so RLS applies. Grant execute to project roles (replace proj_xxxx with your schema from the dashboard):

grants.sql
grant execute on function match_documents(vector, float, int)
  to "proj_xxxx_anon", "proj_xxxx_authenticated";
New functions in the project schema already get EXECUTE via default privileges for anon/authenticated when created by the connection role — still verify with a test rpc() call using the anon key.

7. Metadata filters

Extend the function with extra params (Supabase pattern):

match_filtered.sql
create or replace function match_documents(
  query_embedding vector(1536),
  match_threshold float default 0.7,
  match_count int default 10,
  filter_user_id uuid default null
)
returns table (id uuid, content text, similarity float)
language sql stable
as $$
  select
    documents.id,
    documents.content,
    1 - (documents.embedding <=> query_embedding) as similarity
  from documents
  where
    (filter_user_id is null or documents.user_id = filter_user_id)
    and 1 - (documents.embedding <=> query_embedding) > match_threshold
  order by documents.embedding <=> query_embedding
  limit match_count;
$$;

Next: Semantic search example or Row Level Security.