Postgres & Supabase
The opt-in Postgres path — pgvector-accelerated semantic search for large catalogs, runnable on Supabase. Turso/libSQL stays the zero-config default.
Cartwright runs on Turso (libSQL) by default — managed, edge-replicated, sub-50ms, zero config. You do not need Postgres to run a shop. This page is for one specific case: scaling semantic search on a large catalog by moving the vector nearest-neighbour query into Postgres + pgvector, with Supabase as an easy managed host.
This is an advanced, opt-in path. If you're not running tens of thousands of products with semantic search, stay on Turso — it's simpler and the default everywhere.
Why Postgres for search
Semantic search ranks products by vector similarity. On the default path that scoring runs in TypeScript over the embedding table — linear in catalog size. With pgvector, an HNSW index does approximate-nearest-neighbour search inside the database, so query time scales logarithmically. The ranking formula is identical, so results match the Turso path exactly.
Switch the driver
The driver is selected at runtime — the Turso/SQLite branch always fires first, so existing shops and the canaries are untouched until you opt in.
# .env
DATABASE_DRIVER=postgres
DATABASE_URL=postgresql://... # your Supabase/Postgres connection stringThe Prisma datasource provider must be postgresql for this path (a provider fork, not the default schema). Embeddings are dual-written: the portable ProductEmbedding.vectorJson and a native vector(768) column, so you can move between drivers without re-embedding.
One-time pgvector setup
The extension, the vector column, and the HNSW index live outside Prisma's migration model, so there's a dedicated idempotent script:
pnpm pgvector:setupIt creates the vector extension, adds the embedding vector(768) column to ProductEmbedding, and builds the HNSW index. Safe to re-run.
Then backfill embeddings (if you haven't already):
pnpm embeddings:backfillSupabase specifics
Supabase is plain Postgres with pgvector available, so the steps above apply directly. Two hardening notes for a Supabase project that backs a Cartwright shop:
- Keep Row Level Security on for your tables; Cartwright connects with a privileged server-side connection string, not the anon key.
- Turn the public Data API off (or restrict it) — the storefront and admin reach the database only through Cartwright's server, never the browser.
Falling back is safe: if the Postgres path is unavailable, search degrades to lexical ranking rather than erroring. No data is lost — vectorJson remains the source of truth.