Supabase Vector Database for Production RAG
Use Supabase as the vector store when RAG still belongs in Postgres. Add RLS, HNSW, hybrid search, citations, and exit rules before launch.

Use Supabase as the vector database when RAG still belongs inside your product database. Move retrieval out only when vector search becomes an independent system with its own latency, scale, or operations profile.
The Verdict: Keep RAG In Supabase Until Retrieval Becomes Its Own System
Supabase is the right first production vector store when your documents, tenants, permissions, citations, and product data already belong in Postgres. The reason is not that pgvector magically replaces every vector database. The reason is that most early RAG systems fail at product boundaries before they fail at nearest-neighbor math.
If your knowledge assistant needs tenant-aware retrieval, source citations, document lifecycle rules, admin review, and audit logs, keeping retrieval near the relational data gives you a cleaner system. You can put chunks, embeddings, metadata, source records, permissions, and run logs under the same transaction model and the same security posture. Supabase's AI docs describe the stack as Postgres plus pgvector with client libraries to store, index, and query embeddings at scale.
The line is simple: use Supabase while retrieval is a product feature. Move retrieval out when it becomes its own platform service.
That line usually appears as operational pressure, not as an abstract vector count. Your database CPU is shared with transactional traffic. Your HNSW index has to be rebuilt or tuned. Your p95 retrieval latency starts fighting checkout, billing, or dashboard queries. Your recall tests show that hybrid search, reranking, and metadata filters need a dedicated retrieval pipeline. At that point, a separate vector service may be the cleaner boundary. Until then, another database can add cost and incident surface without solving the harder production problems.
What Supabase Actually Gives The Stack
Supabase gives you managed Postgres with pgvector, not a separate vector engine wearing a Postgres label. That matters because your retrieval code can use normal SQL joins, JSON metadata, row-level security, migrations, backups, and API policies around the vector column.
Supabase describes its vector database feature as a way to keep vector embeddings and relational data in one place, perform similarity search, and combine vector similarity with traditional SQL for hybrid queries. The lower-level vector-column docs are more precise: vectors in Supabase are enabled via pgvector, a Postgres extension for storing and querying vectors in Postgres.
The embedding dimension is not a cosmetic choice. Supabase's vector-column docs say the vector size must match the embedding model. Their example uses extensions.vector(384) for the gte-small model. If you swap embedding models, you either migrate the column or create a parallel embedding column and re-index the table. Silent dimension drift is a deployment bug, not a retrieval-quality problem.
This is also where Supabase has a real advantage for RAG knowledge products. Citations are not just text snippets in a prompt. They are source IDs, chunk IDs, document versions, permissions, and timestamps. Keeping those fields with the embedding lets the application answer: "Which source produced this answer, was the user allowed to see it, and what changed since the answer was generated?"
For teams wiring no-code or workflow automation around retrieval, ecosystem support is useful but should not be the boundary. n8n's Supabase Vector Store node can insert documents, retrieve documents, connect to a retriever, connect directly to an AI agent as a tool, and update an item by ID. That is convenient for internal workflows. Production customer-facing RAG still needs the same schema, RLS, evals, and logging contract underneath.
The Production Schema
The minimum production schema stores the tenant boundary, source identity, chunk identity, content, metadata, full text search materialization, embedding, and timestamps together. Do not start with a minimal documents(content, embedding) table and hope to bolt permissions on later.
Create the retrieval table
Use an explicit tenant key, source key, and chunk key. Keep metadata as
jsonb, but keep the fields you filter on most often as real indexed columns.SQLcreate extension if not exists vector with schema extensions; create table rag_documents ( id uuid primary key default gen_random_uuid(), tenant_id uuid not null, source_id text not null, chunk_id text not null, content text not null, metadata jsonb not null default '{}'::jsonb, fts tsvector generated always as (to_tsvector('english', content)) stored, embedding extensions.vector(384) not null, created_at timestamptz not null default now(), unique (tenant_id, source_id, chunk_id) );The
384dimension matches Supabase'sgte-smallexamples. Change it to the exact dimension your embedding model emits, then treat that value as a migration boundary.Enable RLS before exposing the table
Supabase's RLS docs are blunt: RLS must always be enabled on tables in exposed schemas, and
publicis the default exposed schema. If you create a table with raw SQL, enable RLS yourself.SQLalter table rag_documents enable row level security; create policy "tenant can read own rag chunks" on rag_documents for select to authenticated using (tenant_id = auth.uid());Do not query customer-visible retrieval with a service-role key. Use service-role access for ingestion jobs and admin repair paths, then keep user retrieval behind policies that are tested with the same key class the application will use in production.
Add the indexes that match the retrieval path
Add a tenant index, a GIN index for full text search, and an HNSW index for vector search. Supabase's vector index docs recommend HNSW in general, and pgvector supports HNSW and IVFFlat.
SQLcreate index rag_documents_tenant_idx on rag_documents (tenant_id); create index rag_documents_fts_idx on rag_documents using gin (fts); create index rag_documents_embedding_hnsw_idx on rag_documents using hnsw (embedding vector_cosine_ops);HNSW has a better speed-recall tradeoff than IVFFlat, but it uses more memory and has slower build times. That tradeoff is usually right for a RAG system with changing documents because HNSW does not need a training step before the index can be created.
RLS needs a test, not just a migration. Create separate tenant fixtures, insert chunks for each fixture, authenticate as one tenant, and assert that the match function cannot return another tenant's chunk IDs. Supabase notes that policies act like adding a WHERE clause to every query. Treat that as an implementation detail to verify, not a slogan to trust.
Add HNSW, Then Hybrid Search
Vector-only retrieval is the first version, not the production finish line. It handles semantic matches well, but it misses exact terms that matter in product data: invoice IDs, error strings, SKU codes, feature flags, API names, and legal clause numbers.
Supabase's hybrid search docs combine full text search with semantic search, then fuse the result lists. That is the right shape for a knowledge assistant because it lets exact matches and semantic neighbors compete before the model sees context. The hybrid search rule is still the same: keyword search catches terms the embedding model smooths away, vector search catches meaning the keyword query misses, and a reranker or eval-tuned fusion step decides what enters the prompt.
A practical RPC can return top chunks with both paths represented:
create or replace function match_rag_documents(
query_embedding extensions.vector(384),
query_text text,
match_count int default 8
)
returns table (
id uuid,
source_id text,
chunk_id text,
content text,
metadata jsonb,
retrieval_score double precision
)
language sql
security invoker
set search_path = public, extensions
as $$
with vector_hits as (
select
id,
row_number() over (order by embedding <=> query_embedding) as rank
from rag_documents
order by embedding <=> query_embedding
limit match_count * 4
),
keyword_hits as (
select
id,
row_number() over (
order by ts_rank_cd(fts, websearch_to_tsquery('english', query_text)) desc
) as rank
from rag_documents
where fts @@ websearch_to_tsquery('english', query_text)
limit match_count * 4
),
fused as (
select id, sum(score) as retrieval_score
from (
select id, 1.0 / (60 + rank) as score from vector_hits
union all
select id, 1.0 / (60 + rank) as score from keyword_hits
) scored
group by id
)
select d.id, d.source_id, d.chunk_id, d.content, d.metadata, f.retrieval_score
from fused f
join rag_documents d on d.id = f.id
order by f.retrieval_score desc
limit match_count;
$$;The 60 smoothing value and 8 returned chunks are starting settings, not universal constants. Lock them with an eval set. For a support assistant, include queries with exact product names, typo-heavy user language, "how do I" questions, account-specific terms, and questions where the correct answer is "not enough information." A retrieval eval should score whether the required source chunk appeared, whether forbidden chunks were excluded, and whether the answer cited the exact source version.
What Breaks First In Production
The first production failure is usually not "Supabase cannot store vectors." It is that retrieval competes with product traffic, permissions are tested too late, or quality is judged from demo queries instead of replayable evals.
Resource contention appears when vector queries, full text search, ingestion, and normal app queries share the same Postgres resources. HNSW helps query speed, but it does not make CPU and memory free. Put retrieval latency on the same dashboard as database CPU, memory, index build time, slow queries, and application p95. If the RAG path can degrade the core app, it needs isolation before it needs a new embedding model.
Index drift appears when documents change faster than the team reviews retrieval quality. HNSW is robust for changing data compared with IVFFlat, but every index strategy still needs a release rule. Record the embedding model, chunker version, index type, and migration timestamp. If any of those change, replay the golden retrieval set before launch.
Tenant leakage appears when an ingestion path uses service-role access and the query path is assumed to be safe. Supabase's RLS behavior helps only when the query actually runs under the right role and policies. The release test should include hostile fixtures: same source title across multiple tenants, same file name across multiple tenants, and a query that would retrieve another tenant's chunk if RLS were absent.
Citation drift appears when the retrieved chunk is correct but the visible source link points to an old document, a deleted file, or a page the user cannot open. Store document version and canonical source URL with each chunk. If the source is deleted or permissioned away, either remove the chunk from retrieval or force a re-crawl before it can be cited.
Quality blindness appears when teams log model calls but not retrieval inputs. A generated answer trace is not enough. You need to know which chunks were eligible, which chunks were retrieved, which chunks were sent to the model, which citations were shown, and which answer the user accepted or escalated.
Pricing And Capacity Rules
Supabase pricing should decide environments, not architecture by itself. The Free plan lists 500 MB database size, 5 GB egress, 5 GB cached egress, 1 GB file storage, project pausing after 1 week of inactivity, and a limit of 2 active projects. That is fine for a prototype, not for a production knowledge assistant.
The Pro plan lists 8 GB disk size per project, 250 GB egress, 250 GB cached egress, 100 GB file storage, additional projects from $10 per month, and additional log drains at $60 per drain per project. Those numbers matter because RAG has hidden growth paths: chunk tables, source files, audit logs, trace exports, cached responses, and re-embedding backfills.
Do the first capacity pass from measured rows, not hope:
- Average chunk bytes and embedding dimensions.
- Chunk count per source and per tenant.
- Daily changed chunks.
- Retrieval requests per minute at p95 and peak.
- Index build time after a representative backfill.
- Storage growth from run logs and source snapshots.
The safest budget rule is to pay for boring headroom before launch. If the product database and retrieval workload share the same Supabase project, leave room for ingestion spikes, index builds, and eval replays. If that headroom is politically hard to justify, that is a sign to isolate retrieval earlier, not to run production RAG on prototype limits.
The Exit Rule
Move off Supabase Vector when the retrieval system needs a separate operational boundary. That is the same decision behind the Pgvector vs Pinecone decision: keep retrieval in Postgres while SQL is the product boundary, then move when search becomes the product.
The exit signals are concrete:
- Retrieval needs independent scaling from product Postgres.
- Vector queries regularly threaten transactional workloads.
- Filtering, reranking, or recall requirements are easier to satisfy in a dedicated retrieval service.
- Search incidents need a separate blast radius.
- The team needs specialized vector operations that Postgres should not own.
- A larger eval set proves a dedicated retrieval pipeline improves answer quality enough to justify the extra system.
Do not move because "vector database" sounds more serious. Move because the operational contract changed. A separate vector service brings another vendor, another bill, another migration path, another incident surface, and another place to enforce permissions. Those costs are worth paying when retrieval earns its own boundary. They are waste when the hard work is still chunking, permissions, citations, evals, and logging.
FAQ
Does Supabase have pgvector?
Yes. Supabase vector columns are enabled through pgvector, the Postgres extension for storing and querying vectors. Supabase also documents HNSW and IVFFlat indexes for pgvector.
What are the downsides of Supabase as a vector database?
The downsides are shared database contention, index tuning, and retrieval observability. They are manageable for many production RAG systems, but only if RLS, evals, source citations, and latency dashboards are in place before users depend on the answers.
Is Supabase better than PostgreSQL for RAG?
Supabase is managed Postgres with platform services around it. Choose Supabase when you want managed hosting, APIs, auth integration, and dashboard workflows; choose self-managed Postgres when your team needs direct operations control.
What are the top alternatives to Supabase Vector?
The real alternatives are dedicated vector databases or self-managed Postgres with pgvector. Pick a dedicated vector database when retrieval needs independent scaling, specialized filtering, or isolated operations; keep pgvector when SQL joins, permissions, and product data are the core boundary.
Book the Agentic Readiness Audit
DVNC.dev reviews your AI stack, retrieval boundary, evals, logging, and rollout risk in 5 working days before production traffic depends on it.
Jul 9, 2026


