Supabase
Desplegá este boilerplate contra Supabase Postgres + Supabase Storage con el menor diff de config posible.
Supabase es un target de deploy first-class para este boilerplate. Obtenés Postgres + un bucket de storage S3-compatible de un único vendor, y las abstracciones existentes del boilerplate de Prisma + storage se enchufan sin ningún cambio de código — sólo env vars.
Esta página cubre el path recomendado: Supabase como backend de database y de file-storage, con BetterAuth corriendo encima de Prisma contra la instancia de Postgres de Supabase. No usamos Supabase Auth — BetterAuth ya es dueño de los flows de auth, sessions, y wiring de OAuth en este codebase.
Fuera de scope: Supabase Realtime y Edge Functions. El boilerplate trae su propio stack Socket.IO + BullMQ para esos concerns.
1. Crear un proyecto Supabase
- Iniciá sesión en supabase.com y creá un proyecto nuevo.
- Elegí una contraseña fuerte para la database (la vas a necesitar en el paso 2).
- Esperá a que el proyecto se provisione (~2 minutos).
2. Tomar las connection strings
Abrí Project Settings → Database. Necesitás dos connection strings:
| Variable | Source (Supabase UI) | Por qué |
|---|---|---|
DATABASE_URL | "Connection pooling" → Transaction mode | Pooled (port 6543); usado por la app corriendo para queries cortos |
DIRECT_URL | "Connection string" → URI | Direct (port 5432); usado por prisma migrate para advisory locks |
Agregá ?pgbouncer=true&connect_timeout=15 a DATABASE_URL para que Prisma
sepa que está hablando con un pooler.
# .env (server)
DATABASE_URL="postgresql://postgres.<ref>:<password>@aws-0-<region>.pooler.supabase.com:6543/postgres?pgbouncer=true&connect_timeout=15"
DIRECT_URL="postgresql://postgres.<ref>:<password>@aws-0-<region>.pooler.supabase.com:5432/postgres"¿Por qué dos URLs? El pooler pgbouncer de Supabase desnuda los advisory locks y las sessions long-lived, en los que las migrations de Prisma se apoyan. El runtime usa la URL pooled por eficiencia de conexión; las migrations usan la URL directa. El
prisma/schema.prismablockdatasource dbya declaradirectUrl = env("DIRECT_URL")por esta razón.
3. Correr migrations
Desde la raíz del repo:
bunx prisma migrate deploy --schema apps/server/prisma/schema.prismaPrisma va a usar DIRECT_URL automáticamente. Verificá que las tablas aterrizaron
vía Table Editor en la UI de Supabase.
4. (Opcional) Cambiar storage a Supabase
Si querés que los uploads de avatares y todo upload futuro vayan a Supabase Storage en lugar de S3 / Cloudflare R2 / disco local:
-
Crear un bucket. En Storage → New bucket, nombralo (ej.
avatars). Marcalo "Public" si querés URLs fetcheables desde el browser sin firmar. -
Setear una policy de bucket. Los buckets públicos necesitan una policy
SELECTque otorgue read access de objetos aanon. Los buckets privados no — el adapter mintea URLs firmadas short-lived víapresignDownload.Ejemplo de policy de public-read (correr en SQL Editor):
create policy "public read avatars" on storage.objects for select to public using ( bucket_id = 'avatars' ); -
Tomar la service-role key. Project Settings → API → Service role. Tratala como contraseña de database — sólo server, nunca el browser.
-
Setear env vars.
STORAGE_PROVIDER=supabase SUPABASE_URL=https://<ref>.supabase.co SUPABASE_SERVICE_ROLE_KEY=eyJhbGci... SUPABASE_STORAGE_BUCKET=avatars -
Reiniciá el server. El selector de storage adapter en
apps/server/src/modules/storage/infrastructure/providers/index.tslevantaSTORAGE_PROVIDER=supabasee instancia el adapter de Supabase; si falta alguna var requerida, loggea un warning y cae al provider null no-op para que la secuencia de boot igual complete.
5. Verificar
GET /healthzdebería devolver200.GET /readyzdebería reportardatabase: okystorage: ok(el chequeo de storage pingea el bucket víalist(limit=1)).- Disparar un upload de avatar desde el client; el archivo aparece en
Storage → <bucket>en Supabase.
Lo que deliberadamente saltamos
- Supabase Auth. BetterAuth maneja sessions, OAuth, y magic-link en este boilerplate. Apilar Supabase Auth encima duplicaría esa surface. BetterAuth habla con Supabase Postgres vía Prisma como cualquier otro deployment de Postgres — sin wiring especial.
- Realtime. Usá el server Socket.IO del boilerplate (ya cableado con adapter opcional de Redis para escalado horizontal).
- Edge Functions. El trabajo de background pertenece a workers de BullMQ
(
apps/server/src/bootstrap/worker.ts).
Troubleshooting
prisma migrate deploycuelga o tira error con "advisory lock" — estás apuntando las migrations al pooler. Confirmá queDIRECT_URLuse el port5432(no6543).- El upload de avatar devuelve 500 con
bucket not found— el valor deSUPABASE_STORAGE_BUCKETno matchea un bucket en el proyecto, o la service-role key pertenece a un proyecto distinto. - La URL pública devuelve
403— el bucket es privado y no agregaste una policySELECT. O agregá la policy (arriba) o cambiá el client para fetchear vía la URL firmada que emitepresignDownload.