GitHub ↗

Environment Variables

All environment variables for Momo are documented here. Copy .env.example to .env.local and fill in the values before starting the app.


Required Variables

These must be set for the application to start.

Variable Type Description
DATABASE_URL string (URL) PostgreSQL connection string — postgresql://user:pass@host:port/db
AUTH_SECRET string (min 32 chars) Secret for signing Auth.js JWTs and cookies. Generate with openssl rand -base64 32
AUTH_TRUST_HOST true | false Required in production behind a reverse proxy. Auth.js v5 rejects requests from hosts it doesn’t recognise unless this is true. Set for all Docker Compose + Caddy/nginx deployments and all Kubernetes clusters. Leave false for local development without a proxy.

OAuth Providers

At least one provider must be configured for login to work.

Variable Required Description
GITHUB_CLIENT_ID Optional GitHub OAuth App Client ID
GITHUB_CLIENT_SECRET Optional GitHub OAuth App Client Secret
DISCORD_CLIENT_ID Optional Discord Application Client ID
DISCORD_CLIENT_SECRET Optional Discord Application Client Secret
GOOGLE_CLIENT_ID Optional Google OAuth 2.0 Client ID
GOOGLE_CLIENT_SECRET Optional Google OAuth 2.0 Client Secret
MICROSOFT_CLIENT_ID Optional Microsoft Application (Client) ID — private accounts only (Outlook.com, Hotmail, Live, Xbox). Work / school / Microsoft 365 accounts are intentionally not supported (tenant pinned to consumers). See the Microsoft setup guide.
MICROSOFT_CLIENT_SECRET Optional Microsoft Client Secret Value — make sure you copy the Value column in the Azure portal, not the Secret ID (very common mistake).
OIDC_CLIENT_ID Optional Generic OIDC Client ID (Authentik, Keycloak, Zitadel, etc.)
OIDC_CLIENT_SECRET Optional Generic OIDC Client Secret
OIDC_ISSUER Optional OIDC Issuer URL. Setting this activates the OIDC login button.

See the OAuth Setup guide for provider-specific registration instructions.


Web Push / VAPID

Required only if you want push notification support.

Variable Default Description
NEXT_PUBLIC_VAPID_PUBLIC_KEY VAPID public key (exposed to the browser for push subscriptions)
VAPID_PRIVATE_KEY VAPID private key (server-side only, never exposed to the browser)
VAPID_CONTACT mailto:admin@example.com Contact email or URL for VAPID

Generate a VAPID key pair:

npx web-push generate-vapid-keys

The output will look like:

Public Key:
BExamplePublicKeyHere...

Private Key:
ExamplePrivateKeyHere...

Copy each value to the corresponding variable in .env.local.


Email Notifications (SMTP)

Optional. These variables enable the Email notification channel that users can opt into from Settings → Additional Notification Channels. The channel is hidden in the UI when SMTP_HOST is unset, so leaving these blank is a safe no-op.

Variable Default Description
SMTP_HOST SMTP server hostname (e.g. smtp.gmail.com). Leave empty to disable email notifications.
SMTP_PORT 587 SMTP port. 587 for STARTTLS, 465 for implicit TLS.
SMTP_USER SMTP authentication username. Optional if your SMTP server allows unauthenticated relay (e.g. local Mailpit).
SMTP_PASS SMTP authentication password / app password.
SMTP_FROM Sender address used as the From: header, e.g. "Momo <noreply@momotask.app>". Required for delivery.
SMTP_SECURE false true for implicit TLS (port 465), false for STARTTLS (port 587).

Gmail with App Password:

SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=you@gmail.com
SMTP_PASS=xxxxxxxxxxxxxxxx          # 16-char Google App Password
SMTP_FROM="Momo <you@gmail.com>"
SMTP_SECURE=false

Mailpit (local development, no auth):

SMTP_HOST=localhost
SMTP_PORT=1025
SMTP_FROM="Momo <noreply@localhost>"
SMTP_SECURE=false

Run Mailpit with docker run -p 1025:1025 -p 8025:8025 axllent/mailpit and view captured emails at http://localhost:8025.

The other notification channels (ntfy.sh, Pushover, Telegram) are configured per user in the settings UI — no environment variables needed.


Cron Job Protection

Variable Default Description
CRON_SECRET Bearer token required by POST /api/cron. Include as Authorization: Bearer <token>. Generate with openssl rand -hex 32. If unset, the cron route is unprotected.

Protect the cron route in production:

CRON_SECRET=$(openssl rand -hex 32)

Call the unified cron dispatcher:

curl -X POST https://your-domain.com/api/cron \
  -H "Authorization: Bearer $CRON_SECRET"

Application

Variable Default Description
NEXT_PUBLIC_APP_URL http://localhost:3000 Public URL of the application. Used for notification links, the PWA, and SEO (robots.txt, sitemap.xml, Open Graph tags, JSON-LD). Set this to your real HTTPS origin in production or search engines will index localhost.
NEXTAUTH_URL http://localhost:3000 Auth.js callback base URL. Must exactly match the Homepage URL and Authorized redirect URI configured in each OAuth provider app. In production: https://your-domain.com
NODE_ENV development Runtime environment: development, production, or test. Set to production in all production deployments.
DISABLE_UPDATE_CHECK false Set to true to disable the automatic update check. When enabled, Momo queries the GitHub Releases API once per 24 hours and shows a banner in the Admin panel when a newer version is available. Disable this for air-gap or offline installations where outbound access to api.github.com is not permitted.

In production, set both NEXT_PUBLIC_APP_URL and NEXTAUTH_URL to your public HTTPS domain:

NEXT_PUBLIC_APP_URL=https://momo.example.com
NEXTAUTH_URL=https://momo.example.com

Two-Factor Authentication

Optional. The TOTP feature is fully self-contained — no external services required.

Variable Default Description
TOTP_ENCRYPTION_KEY AES-256-GCM key used to encrypt TOTP secrets at rest in the database. Required as soon as any user enables 2FA, or when REQUIRE_2FA=true. Must be exactly 64 hex characters (32 bytes). Generate with openssl rand -hex 32. Treat this as critical secret material — rotating it invalidates every existing TOTP secret and forces every user to re-enroll.
REQUIRE_2FA false When true, every user must register a second factor (TOTP or Passkey) before they can access any protected route. Existing users without a second factor are hard-locked to a forced setup page on their next login. Removing the last remaining second factor is blocked, both in the UI and by a 403 at the API.
WEBAUTHN_RP_ID hostname of NEXT_PUBLIC_APP_URL WebAuthn Relying Party ID. Must be the eTLD+1 hostname of your site (no scheme, no port, no path) — for example momotask.app, or localhost during development. A mismatch with the actual origin breaks passkey registration and login.
WEBAUTHN_RP_NAME Momo Display name shown in the OS / browser passkey prompt. Purely cosmetic.

Setting REQUIRE_2FA=true without TOTP_ENCRYPTION_KEY will refuse to start. Make sure both are present.

End-user guide → Two-Factor Authentication · Passkeys Operator guide → Self-Hosting → Enforcing two-factor authentication


Admin Access

Variable Default Description
ADMIN_USER_IDS Comma-separated list of user UUIDs that can access the /admin aggregate-statistics page. If unset or empty, the admin page is inaccessible to everyone.

Example with two admins:

ADMIN_USER_IDS=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy

Find a user’s UUID in the database with SELECT id, email FROM users;.


Required for publicly accessible deployments in Germany and recommended everywhere. These values are rendered on /impressum and /datenschutz. If unset, those pages show a configuration warning instead of legal content.

Variable Required Description
NEXT_PUBLIC_IMPRINT_NAME Public deployments Full legal name of the operator (§ 5 TMG)
NEXT_PUBLIC_IMPRINT_ADDRESS Public deployments Street address, postcode, city
NEXT_PUBLIC_IMPRINT_EMAIL Public deployments Contact / data protection email address
NEXT_PUBLIC_IMPRINT_PHONE Optional Phone number (recommended for § 5 TMG)

Docker Compose

Variable Default Description
POSTGRES_PASSWORD password PostgreSQL password used by docker-compose.yml for the db service. Must match the password in DATABASE_URL.

Complete Example

A minimal .env.local for local development with GitHub OAuth:

# Database
DATABASE_URL=postgresql://momo:password@db:5432/momo
POSTGRES_PASSWORD=password

# Auth
AUTH_SECRET=replace-this-with-openssl-rand-base64-32-output
AUTH_TRUST_HOST=false

# GitHub OAuth
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret

# URLs
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXTAUTH_URL=http://localhost:3000

A production .env.local with all features enabled (behind a reverse proxy):

# Database
DATABASE_URL=postgresql://momo:strongpassword@db:5432/momo
POSTGRES_PASSWORD=strongpassword

# Auth
AUTH_SECRET=your-32-byte-base64-secret
AUTH_TRUST_HOST=true

# OAuth
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret
DISCORD_CLIENT_ID=your-discord-client-id
DISCORD_CLIENT_SECRET=your-discord-client-secret

# VAPID (push notifications)
NEXT_PUBLIC_VAPID_PUBLIC_KEY=your-vapid-public-key
VAPID_PRIVATE_KEY=your-vapid-private-key
VAPID_CONTACT=mailto:admin@example.com

# Email notifications (optional — enables the Email channel in user settings)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=you@gmail.com
SMTP_PASS=your-smtp-app-password
SMTP_FROM="Momo <you@gmail.com>"
SMTP_SECURE=false

# Cron protection
CRON_SECRET=your-hex-cron-secret

# Two-factor authentication (required if any user enables 2FA, or REQUIRE_2FA=true)
TOTP_ENCRYPTION_KEY=64-hex-characters-from-openssl-rand-hex-32
REQUIRE_2FA=false

# Passkeys (optional — auto-derived from NEXT_PUBLIC_APP_URL when unset)
WEBAUTHN_RP_ID=momo.example.com
WEBAUTHN_RP_NAME=Momo

# URLs
NEXT_PUBLIC_APP_URL=https://momo.example.com
NEXTAUTH_URL=https://momo.example.com
NODE_ENV=production

# Legal pages (required for public deployments in Germany)
NEXT_PUBLIC_IMPRINT_NAME=Max Mustermann
NEXT_PUBLIC_IMPRINT_ADDRESS=Musterstraße 1, 12345 Berlin
NEXT_PUBLIC_IMPRINT_EMAIL=kontakt@example.com
NEXT_PUBLIC_IMPRINT_PHONE=+49 30 123456