Supabase
Faça deploy deste boilerplate contra Supabase Postgres + Supabase Storage com o menor diff de config possível.
Supabase é um target de deploy first-class para este boilerplate. Você obtém Postgres + um bucket de storage S3-compatible de um único vendor, e as abstrações existentes do boilerplate de Prisma + storage encaixam sem nenhuma mudança de código — apenas env vars.
Esta página cobre o path recomendado: Supabase como backend de database e file-storage, com BetterAuth rodando em cima de Prisma contra a instância Postgres do Supabase. Não usamos Supabase Auth — BetterAuth já é dono dos flows de auth, sessions, e wiring de OAuth neste codebase.
Fora de escopo: Supabase Realtime e Edge Functions. O boilerplate entrega seu próprio stack Socket.IO + BullMQ para esses concerns.
1. Criar um projeto Supabase
- Faça login em supabase.com e crie um novo projeto.
- Escolha uma senha forte para o database (você vai precisar no passo 2).
- Espere o projeto provisionar (~2 minutos).
2. Pegar as connection strings
Abra Project Settings → Database. Você precisa de duas connection strings:
| Variável | Source (Supabase UI) | Por quê |
|---|---|---|
DATABASE_URL | "Connection pooling" → Transaction mode | Pooled (port 6543); usado pela app rodando para queries curtas |
DIRECT_URL | "Connection string" → URI | Direct (port 5432); usado por prisma migrate para advisory locks |
Anexe ?pgbouncer=true&connect_timeout=15 ao DATABASE_URL para que o Prisma
saiba que está falando com um 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 que duas URLs? O pooler pgbouncer do Supabase remove advisory locks e sessions long-lived, dos quais migrations Prisma dependem. O runtime usa a URL pooled por eficiência de conexão; migrations usam a URL direta. O block
datasource dbemprisma/schema.prismajá declaradirectUrl = env("DIRECT_URL")por essa razão.
3. Rodar migrations
Da raiz do repo:
bunx prisma migrate deploy --schema apps/server/prisma/schema.prismaO Prisma vai usar DIRECT_URL automaticamente. Verifique que as tabelas
chegaram via Table Editor na UI do Supabase.
4. (Opcional) Trocar storage para Supabase
Se você quer que uploads de avatar e quaisquer uploads futuros vão para Supabase Storage em vez de S3 / Cloudflare R2 / disco local:
-
Criar um bucket. Em Storage → New bucket, nomeie (ex.
avatars). Marque "Public" se você quer URLs fetchable pelo browser sem assinar. -
Definir uma policy de bucket. Buckets públicos precisam de uma policy
SELECTconcedendo read access de objetos paraanon. Buckets privados não — o adapter cunha URLs assinadas short-lived viapresignDownload.Exemplo de policy public-read (rode no SQL Editor):
create policy "public read avatars" on storage.objects for select to public using ( bucket_id = 'avatars' ); -
Pegue a service-role key. Project Settings → API → Service role. Trate como senha de database — server-only, nunca no browser.
-
Definir env vars.
STORAGE_PROVIDER=supabase SUPABASE_URL=https://<ref>.supabase.co SUPABASE_SERVICE_ROLE_KEY=eyJhbGci... SUPABASE_STORAGE_BUCKET=avatars -
Reinicie o server. O seletor de storage adapter em
apps/server/src/modules/storage/infrastructure/providers/index.tspegaSTORAGE_PROVIDER=supabasee instancia o adapter Supabase; se alguma var obrigatória estiver faltando, loga um warning e cai para o provider null no-op para que a sequência de boot ainda complete.
5. Verificar
GET /healthzdeve retornar200.GET /readyzdeve reportardatabase: okestorage: ok(o check de storage pinga o bucket vialist(limit=1)).- Dispare um upload de avatar do client; o arquivo aparece em
Storage → <bucket>no Supabase.
O que pulamos deliberadamente
- Supabase Auth. BetterAuth gerencia sessions, OAuth, e magic-link neste boilerplate. Empilhar Supabase Auth em cima duplicaria essa surface. BetterAuth fala com Supabase Postgres via Prisma como qualquer outro deployment Postgres — sem wiring especial.
- Realtime. Use o server Socket.IO do boilerplate (já cabeado com adapter opcional Redis para escala horizontal).
- Edge Functions. Trabalho de background pertence a workers BullMQ
(
apps/server/src/bootstrap/worker.ts).
Troubleshooting
prisma migrate deploytrava ou erra com "advisory lock" — você está apontando migrations ao pooler. Confirme queDIRECT_URLusa port5432(não6543).- Upload de avatar retorna 500 com
bucket not found— o valor deSUPABASE_STORAGE_BUCKETnão bate com um bucket no projeto, ou a service-role key pertence a um projeto diferente. - URL pública retorna
403— bucket é privado e você não adicionou uma policySELECT. Ou adicione a policy (acima) ou troque o client para fetchar via a URL assinada emitida porpresignDownload.