Docker
Suba o stack completo (Postgres, Redis, server, client) com um único comando para desenvolvimento local ou builds production-like.
O repo entrega dois arquivos Compose. Escolha o que combina com o que você precisa:
| Arquivo | Propósito | O que inclui |
|---|---|---|
docker-compose.dev.yml | Desenvolvimento local. Hot reload, source montado, secrets efêmeros. | Postgres 16 · Redis 7 · server (Bun + --hot) · client (next dev) |
docker-compose.yml | Build production-like. Imagens standalone, sem source montado, sem DB. | imagem do server · imagem do client (você traz seu Postgres + Redis) |
Se você quer experimentar o boilerplate de ponta a ponta sem provisionar nada, use
docker-compose.dev.yml— sobe o stack inteiro.
Quick start (desenvolvimento)
Da raiz do repo:
docker compose -f docker-compose.dev.yml upEsse único comando não builda nada — puxa imagens públicas e monta sua working tree. Espere ~30 segundos para que bun install termine dentro de ambos os containers.
Você obtém:
| Serviço | URL / Port | Notas |
|---|---|---|
| Client | http://localhost:3004 | Next.js com hot reload |
| Server | http://localhost:3005 | Express em Bun, hot reload via bun --hot |
| Postgres | postgresql://postgres:postgres@localhost:5432/boilerplate | Usuário/pass/db são seedados pelo arquivo compose |
| Redis | redis://localhost:6379 | Usado por BullMQ + store de rate-limit |
O server lê sua config a partir de variáveis de ambiente embutidas no arquivo compose — sem .env necessário para subir.
[!NOTE] O container do client precisa de duas URLs da API no compose:
NEXT_PUBLIC_API_URL=http://localhost:3005para o browser, eINTERNAL_API_URL=http://server:3005para os fetches do middleware / RSC do Next.js que rodam dentro do container. Setups single-host (Vercel, bare-metal) só precisam deNEXT_PUBLIC_API_URL— o middleware faz fallback para essa quandoINTERNAL_API_URLnão está setada.
Primeiro run — aplicar migrations
O arquivo compose inicia o server mas não roda as migrations Prisma automaticamente (para você escolher a estratégia certa para seu branch). No primeiro boot, em um segundo terminal:
docker compose -f docker-compose.dev.yml exec server \
bunx --cwd apps/server prisma migrate deployPara um schema fresco durante desenvolvimento você pode usar migrate dev em vez disso — isso cria uma nova migration a partir do seu schema.prisma atual:
docker compose -f docker-compose.dev.yml exec server \
bunx --cwd apps/server prisma migrate devPrimeiro run — seed de roles + permissions
O boilerplate entrega um script de seed que cria os roles default owner / admin / member para o módulo IAM. Rode uma vez:
docker compose -f docker-compose.dev.yml exec server \
bun apps/server/prisma/seed.tsPronto. Cadastre-se em http://localhost:3004/register e você vai cair no dashboard.
Comandos comuns
# Tail dos logs do server (o mais útil)
docker compose -f docker-compose.dev.yml logs -f server
# Abrir um shell dentro do container do server (debug Prisma, rodar scripts, etc.)
docker compose -f docker-compose.dev.yml exec server sh
# Conectar ao Postgres com psql
docker compose -f docker-compose.dev.yml exec postgres \
psql -U postgres -d boilerplate
# Parar tudo (os containers ficam — `up` da próxima vez é mais rápido)
docker compose -f docker-compose.dev.yml stop
# Derrubar tudo INCLUINDO o volume do Postgres (destrói dados)
docker compose -f docker-compose.dev.yml down -vServiços opcionais
O compose dev mantém a surface pequena de propósito. Se você precisa dos adapters opcionais que vêm com o boilerplate, adicione você mesmo:
- BullMQ Bull Board — sobe dentro do container do server automaticamente quando
REDIS_URLestá definido; visite http://localhost:3005/admin/queues. - Mailpit / MailHog para capturar emails de dev — adicione um service block, depois defina
EMAIL_FROM=dev@locale (se usando Resend) deixeRESEND_API_KEYvazio para que oLogEmailProviderassuma. - MongoDB — o arquivo compose tem um block
mongodbcomentado. Descomente, siga ADR-002 para trocar o provider Prisma, e atualizeDATABASE_URL.
Build production-like
O outro arquivo compose (docker-compose.yml) builda imagens imutáveis de server e client — útil para verificar que seu código passa pelo mesmo build pipeline que o CI usa, ou para fazer push para um registry.
# Provisione seu próprio Postgres + Redis primeiro, depois exporte suas URLs:
export DATABASE_URL=postgresql://...
export REDIS_URL=redis://...
export BETTER_AUTH_SECRET=$(openssl rand -hex 32)
docker compose up --buildIsso não inclui um database — o compose de prod assume que você está rodando contra Postgres gerenciado (Supabase, Neon, RDS, etc.) e Redis gerenciado (Upstash, ElastiCache, etc.). Veja o guia do Supabase para um setup de um vendor só.
A imagem do server roda prisma migrate deploy no boot, então migrations se aplicam automaticamente contra o DATABASE_URL configurado.
Troubleshooting
port is already allocated — algo no seu host está usando 3004, 3005, 5432, ou 6379. Ou pare ou remapeie o port host-side no arquivo compose ("3104:3004").
O server sobe mas toda request dá 500 com "Cannot find module '@prisma/client'" — o client Prisma não foi gerado. O container dev roda bun install no boot que dispara o postinstall hook; se correu junto com a primeira request, reinicie o server: docker compose -f docker-compose.dev.yml restart server.
Hot reload não pega mudanças no macOS — o filesystem polling do Docker Desktop é lento. O arquivo compose monta o repo inteiro com volumes: - .:/app; se você vê lag, troque o Docker Desktop para VirtioFS (Settings → General → Virtual Machine Manager).
Migrations falham com "database does not exist" — o healthcheck do Postgres reporta ready antes do database boilerplate ser criado no primeiro boot. Espere 5 segundos e tente o comando migrate novamente.
bun install roda toda vez e é lento — esperado: o compose monta um volume para node_modules para que persista entre restarts, mas o primeiro install paga o custo completo de rede. Boots subsequentes reusam o volume.
Um container sumiu no meio da execução e voltou sozinho — server, worker e client têm restart: unless-stopped no compose de dev. É intencional: suites E2E pesadas podem OOM-killar o processo do Bun sob fluxos de auth concorrentes + enfileiramentos do BullMQ, e o auto-restart evita rodar docker start na mão. Se um container reinicia repetidamente, siga os logs (logs -f <service>) — você tem um crash real, não um one-off.