SaaS Starter

Entorno

Variables de entorno requeridas y opcionales. El schema en apps/server/src/bootstrap/env.ts es la fuente de verdad.

Todas las env vars son validadas por un schema Zod en apps/server/src/bootstrap/env.ts. El servidor falla al arrancar con un error claro si falta una variable requerida o está mal formada. Los adapters opcionales arrancan como no-op cuando su configuración está sin definir — nunca necesitás llenar todas las claves.

Mínimo para arrancar

Estas cuatro son el piso. Sin ellas el servidor sale temprano:

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

Generá el auth secret con openssl rand -base64 32. CORS_ORIGINS es una lista separada por comas de los origins permitidos para el browser.

Auth providers (opcional)

GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=

Dejá ambos vacíos para deshabilitar Google OAuth. El magic link se configura a través de tu provider de email — ver el 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=             # ponelo para R2/MinIO; dejalo vacío para AWS
STORAGE_S3_PUBLIC_BASE_URL=      # base del CDN
# Disco local (dev)
STORAGE_LOCAL_ROOT=
STORAGE_LOCAL_PUBLIC_BASE_URL=
# UploadThing
UPLOADTHING_TOKEN=
UPLOADTHING_APP_ID=

STORAGE_PROVIDER=null (el default) saltea el registro de un adapter, así que los endpoints que necesitan uploads devuelven 503. El provider local arma URLs públicas desde BETTER_AUTH_URL (la URL del server), no APP_URL — los uploads los sirve la API, no Next.js.

Background jobs (opcional)

REDIS_URL=redis://localhost:6379
JOBS_REDIS_URL=                  # default a REDIS_URL
JOBS_PREFIX=bull
BULL_BOARD_ENABLED=true          # monta la UI de /admin/queues

Sin Redis, BullMQ se registra pero ningún worker conecta. BULL_BOARD_ENABLED=true monta una UI de Bull Board protegida en /admin/queues.

Rate limiting

RATE_LIMIT_REDIS_ENABLED=true    # cae a memoria cuando REDIS_URL no está
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

Los cuatro tiers (read, write, auth-ip, auth-email) tienen cada uno su propio prefijo de Redis (rl:read:, rl:write:, etc.) así los counters nunca colisionan. Los handlers del limiter se memoizan sobre la referencia RateLimitDeps, así el modo memoria se comporta idéntico al modo Redis (un store compartido por tier).

Observabilidad (opcional)

SENTRY_DSN=                      # dejalo vacío para deshabilitar
SENTRY_TRACES_SAMPLE_RATE=0.1
APP_VERSION=

OTEL_EXPORTER_OTLP_ENDPOINT=     # dejalo vacío para deshabilitar trace export
OTEL_SERVICE_NAME=mern-saas-server

METRICS_ENABLED=true             # endpoint /metrics de Prometheus

OTel debe arrancar antes de que se carguen Express/Prisma. El primer import en apps/server/src/index.ts es ./otel-init.js por eso. No lo reordenes.

El SDK de Sentry server es @sentry/bun (no @sentry/node). logger.error(...) no auto-captura; usá el helper captureError(err, ctx) para errores que deban paginar a alguien.

Billing (depende del provider)

Configurá PAYMENT_PROVIDER con uno de stripe, mercado-pago, polar, después llená las claves de ese provider:

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

Ver Billing para la estrategia y el setup de webhooks.

Usage metering (opcional)

Deshabilitado por default. Activá el flag una vez que el downstream registró sus meters y un mapa plan → cap.

USAGE_METERING_ENABLED=false               # poné "true" para enforzar cuotas
USAGE_FREE_PRICE_ID=price_free_synthetic   # key sintético del tier Free; no es un price real de Polar

Ver Usage metering para la referencia completa.

Agregar una nueva variable

  1. Editá apps/server/src/bootstrap/env.ts y extendé el schema Zod. Las vars requeridas deben tener .min(1); las opcionales usan .optional() o .default(...).
  2. Agregá una entrada documentada en apps/server/.env.example.
  3. Leela desde env.YOUR_VAR — nunca desde process.env directo.

En esta página