Skip to content

Production Setup

  • Node.js 20+
  • PostgreSQL 14+
  • A domain with wildcard DNS or multiple subdomains

For SSO to work, all SaaS frontends and saas-core must share a parent domain:

auth.example.com → saas-core instance
tobby.example.com → Acme frontend
studio.example.com → Beta frontend

The session cookie is set with Domain=.example.com, which means all *.example.com subdomains receive it.

HTTPS is required for:

  1. Secure cookies — Better Auth uses __Secure- prefixed cookies in production, which require HTTPS
  2. OAuth redirects — Google, Apple, and GitHub require HTTPS callback URLs
  3. CORS — Modern browsers enforce same-origin policies over HTTPS

Use a reverse proxy (Caddy, Nginx, Cloudflare) to terminate TLS.

PORT=3000
DATABASE_URL=postgresql://user:pass@host:5432/saas_core
LOG_LEVEL=info
ADMIN_TOKEN=<openssl rand -hex 32>
BETTER_AUTH_SECRET=<openssl rand -hex 32>
BETTER_AUTH_BASE_URL=https://auth.example.com
AUTH_COOKIE_DOMAIN=.example.com
SAAS_TRUSTED_ORIGINS=https://tobby.example.com,https://studio.example.com
OAUTH_LOGIN_PAGE=/login
OAUTH_CONSENT_PAGE=/consent

Recommended: use a process manager (systemd, PM2) to keep saas-core running:

Terminal window
# systemd unit example
[Unit]
Description=saas-core
After=network.target postgresql.service
[Service]
Type=simple
User=deploy
WorkingDirectory=/opt/saas-core
ExecStart=/usr/bin/node /opt/saas-core/dist/server.js
EnvironmentFile=/opt/saas-core/.env
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Terminal window
npm run build # Builds the backend to dist/
npm -w saas-admin run build # Builds the admin console

Run migrations on deploy:

Terminal window
npm run db:migrate

This is idempotent — safe to run on every deploy.