SaaS Starter

Ambiente

Variáveis de ambiente obrigatórias e opcionais. O schema em apps/server/src/bootstrap/env.ts é a fonte de verdade.

Todas as env vars são validadas por um schema Zod em apps/server/src/bootstrap/env.ts. O servidor falha na inicialização com um erro claro se uma var obrigatória estiver faltando ou malformada. Adapters opcionais sobem como no-op quando sua configuração está vazia — você nunca precisa preencher todas as chaves.

Mínimo para subir

Estas quatro são o piso. Sem elas o servidor sai cedo:

BETTER_AUTH_SECRET=<openssl rand -base64 32>
BETTER_AUTH_URL=http://localhost:3005
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/boilerplate?schema=public
CORS_ORIGINS=http://localhost:3004

Gere o auth secret com openssl rand -base64 32. CORS_ORIGINS é uma lista separada por vírgula de origins permitidos para o browser.

Auth providers (opcional)

GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=

Deixe ambos vazios para desabilitar o Google OAuth. O magic link é configurado via seu provider de email — veja o módulo notifications.

Storage (opcional)

STORAGE_PROVIDER=null            # null | local | s3 | uploadthing
# S3 / R2 / MinIO
STORAGE_S3_BUCKET=
STORAGE_S3_REGION=
STORAGE_S3_ACCESS_KEY_ID=
STORAGE_S3_SECRET_ACCESS_KEY=
STORAGE_S3_ENDPOINT=             # defina para R2/MinIO; deixe vazio para AWS
STORAGE_S3_PUBLIC_BASE_URL=      # base do CDN
# Disco local (dev)
STORAGE_LOCAL_ROOT=
STORAGE_LOCAL_PUBLIC_BASE_URL=
# UploadThing
UPLOADTHING_TOKEN=
UPLOADTHING_APP_ID=

STORAGE_PROVIDER=null (o default) pula o registro de um adapter, então endpoints que precisam de uploads retornam 503. O provider local constrói URLs públicas a partir de BETTER_AUTH_URL (a URL do server), não APP_URL — uploads são servidos pela API, não pelo Next.js.

Background jobs (opcional)

REDIS_URL=redis://localhost:6379
JOBS_REDIS_URL=                  # padrão: REDIS_URL
JOBS_PREFIX=bull
BULL_BOARD_ENABLED=true          # monta a UI em /admin/queues

Sem Redis, o BullMQ é registrado mas nenhum worker conecta. BULL_BOARD_ENABLED=true monta uma UI Bull Board protegida em /admin/queues.

Rate limiting

RATE_LIMIT_REDIS_ENABLED=true    # cai para memória quando REDIS_URL está vazio
RATE_LIMIT_READ_PER_MIN=300
RATE_LIMIT_WRITE_PER_MIN=60
RATE_LIMIT_AUTH_IP_PER_MIN=30
RATE_LIMIT_AUTH_EMAIL_PER_15MIN=5

Os quatro tiers (read, write, auth-ip, auth-email) têm cada um seu próprio prefixo Redis (rl:read:, rl:write:, etc.) para que os counters nunca colidam. Os handlers do limiter são memoizados sobre a referência RateLimitDeps, fazendo com que o modo memória se comporte de forma idêntica ao modo Redis (um store compartilhado por tier).

Observabilidade (opcional)

SENTRY_DSN=                      # deixe vazio para desabilitar
SENTRY_TRACES_SAMPLE_RATE=0.1
APP_VERSION=

OTEL_EXPORTER_OTLP_ENDPOINT=     # deixe vazio para desabilitar trace export
OTEL_SERVICE_NAME=mern-saas-server

METRICS_ENABLED=true             # endpoint /metrics do Prometheus

O OTel deve subir antes de Express/Prisma carregarem. O primeiro import em apps/server/src/index.ts é ./otel-init.js por causa disso. Não reordene.

O Sentry server SDK é @sentry/bun (não @sentry/node). logger.error(...) não auto-captura; use o helper captureError(err, ctx) para erros que devem paginar alguém.

Billing (depende do provider)

Defina PAYMENT_PROVIDER como um de stripe, mercado-pago, polar, depois preencha as chaves desse provider:

PAYMENT_PROVIDER=stripe
STRIPE_SECRET_KEY=
STRIPE_WEBHOOK_SECRET=
# ou
PAYMENT_PROVIDER=mercado-pago
MERCADO_PAGO_ACCESS_TOKEN=
MERCADO_PAGO_WEBHOOK_SECRET=
# ou
PAYMENT_PROVIDER=polar
POLAR_ACCESS_TOKEN=
POLAR_WEBHOOK_SECRET=

Veja Billing para a estratégia e setup de webhooks.

Usage metering (opcional)

Desabilitado por default. Ative a flag depois que o downstream registrar seus meters e um mapa plano → cap.

USAGE_METERING_ENABLED=false               # defina "true" para enforçar cotas
USAGE_FREE_PRICE_ID=price_free_synthetic   # chave sintética do tier Free; não é um price real do Polar

Veja Usage metering para a referência completa.

Adicionando uma nova variável

  1. Edite apps/server/src/bootstrap/env.ts e estenda o schema Zod. Vars obrigatórias precisam de .min(1); opcionais usam .optional() ou .default(...).
  2. Adicione uma entrada documentada em apps/server/.env.example.
  3. Leia de env.YOUR_VAR — nunca de process.env diretamente.

Nesta página