Skip to main content
PlanningSup is configured through environment variables defined in apps/api/.env. This page documents all available options.

Quick reference

Copy .env.example to .env and customize for your environment:
cp apps/api/.env.example apps/api/.env

Database

DATABASE_URL
string
required
PostgreSQL connection string.Default (development):
DATABASE_URL=postgres://planningsup:mysecretpassword@localhost:5432/planningsup
Production example:
DATABASE_URL=postgres://user:password@postgres:5432/planningsup
Format:
postgres://username:password@host:port/database
NO_MIGRATE_DATABASE
boolean
default:"false"
Skip automatic database migrations on startup.
NO_MIGRATE_DATABASE=true
Only disable migrations if you’re running them manually. The API expects the latest schema.

Server

PORT
number
default:"20000"
Port the API server listens on.
PORT=20000
In Docker, this is typically 20000 internally, mapped to a different port externally:
ports:
  - '31021:20000'
PUBLIC_ORIGIN
string
Public-facing URL of your PlanningSup instance. Required in production for:
  • SEO (robots.txt, sitemap.xml)
  • OAuth callbacks
  • WebAuthn (passkey authentication)
PUBLIC_ORIGIN=https://planningsup.example.com
Omit trailing slash. Use full URL including protocol.
TRUSTED_ORIGINS
string
Comma-separated list of origins allowed for CORS and OAuth redirects.Development example:
TRUSTED_ORIGINS=http://localhost:1420,http://localhost:4444,http://localhost:20000,http://tauri.localhost,tauri://localhost,planningsup://auth-callback/discord
Production example:
TRUSTED_ORIGINS=https://planningsup.example.com
Include all frontend origins: web app, Tauri desktop app, browser extension deep links.
NODE_ENV
string
default:"development"
Environment mode. Set to production for production deployments.
NODE_ENV=production
Affects:
  • Logging verbosity
  • Error response details
  • Static file serving
  • OPS_TOKEN requirement

Authentication

AUTH_ENABLED
boolean
default:"false"
Enable BetterAuth authentication features (OAuth, passkeys, user preferences sync).
AUTH_ENABLED=true
When enabled, requires additional auth variables below.
BETTER_AUTH_SECRET
string
Secret key for signing authentication tokens. Required when AUTH_ENABLED=true.
BETTER_AUTH_SECRET=your-random-secret-key-here
Generate a strong random value (at least 32 characters). Never commit this to version control.
BETTER_AUTH_URL
string
Base URL for BetterAuth endpoints. Should match your API URL.
BETTER_AUTH_URL=http://localhost:20000
In production:
BETTER_AUTH_URL=https://planningsup.example.com

OAuth providers

DISCORD_CLIENT_ID
string
Discord OAuth application client ID.
DISCORD_CLIENT_ID=your-discord-client-id
Create an app at: https://discord.com/developers/applications
DISCORD_CLIENT_SECRET
string
Discord OAuth application client secret.
DISCORD_CLIENT_SECRET=your-discord-client-secret
GITHUB_CLIENT_ID
string
GitHub OAuth application client ID.
GITHUB_CLIENT_ID=your-github-client-id
Create an app at: https://github.com/settings/developers
GITHUB_CLIENT_SECRET
string
GitHub OAuth application client secret.
GITHUB_CLIENT_SECRET=your-github-client-secret

Background jobs

RUN_JOBS
boolean
default:"false"
Enable background job workers for planning refresh and backfill.
RUN_JOBS=true
Jobs:
  • plannings-backfill: Ensures all plannings have database backups
  • plannings-refresh-worker: Processes refresh queue for stale plannings
JOBS_QUIET_HOURS
string
Time window to reduce job activity (e.g., overnight). Format: HH:MM-HH:MM.
JOBS_QUIET_HOURS=21:00-06:00
During quiet hours:
  • Refresh intervals are extended
  • Background activity is minimized
Times are in the server’s local timezone.
ALLOWED_JOBS
string
Comma-separated list of jobs to run. Omit to run all jobs.
ALLOWED_JOBS=plannings-backfill,plannings-refresh-worker
Available jobs:
  • plannings-backfill
  • plannings-refresh-worker

Job tuning parameters

PLANNINGS_BACKFILL_INTERVAL_MS
number
default:"600000"
Interval between backfill job runs (milliseconds).
PLANNINGS_BACKFILL_INTERVAL_MS=600000  # 10 minutes
PLANNINGS_REFRESH_WORKER_MAX_POLL_MS
number
default:"30000"
Maximum time refresh worker waits for queue items (milliseconds).
PLANNINGS_REFRESH_WORKER_MAX_POLL_MS=30000  # 30 seconds
PLANNINGS_REFRESH_WORKER_MAX_ATTEMPTS
number
default:"10"
Maximum retry attempts for failed planning refreshes.
PLANNINGS_REFRESH_WORKER_MAX_ATTEMPTS=10

Operations

OPS_TOKEN
string
Secret token for accessing operations endpoints (/api/ops/*).
OPS_TOKEN=your-secret-ops-token
Usage:
curl -H "x-ops-token: your-secret-ops-token" https://planningsup.example.com/api/ops/plannings
In production, OPS_TOKEN is required. In development, operations endpoints are open if OPS_TOKEN is not set.

Planning data

PLANNINGS_LOCATION
string
default:"/app/plannings"
Directory containing planning JSON files.Default (Docker):
PLANNINGS_LOCATION=/app/plannings
Development:
PLANNINGS_LOCATION=./resources/plannings
Planning files are loaded at startup from this directory.
WEB_DIST_LOCATION
string
default:"/app/web/dist"
Directory containing built frontend static files.Default (Docker):
WEB_DIST_LOCATION=/app/web/dist
In production, the API serves the PWA from this location.

Extensions and integrations

CHROME_EXTENSION_ID
string
Chrome Web Store extension ID for browser extension integration.
CHROME_EXTENSION_ID=bcjhdlcgblcphljokeippholkfifdbod
Used for:
  • Extension OAuth callbacks
  • Deep link handling

Analytics

PLAUSIBLE_DOMAIN
string
Domain name for Plausible Analytics tracking.
PLAUSIBLE_DOMAIN=planningsup.example.com
PLAUSIBLE_ENDPOINT
string
Custom Plausible Analytics endpoint URL.
PLAUSIBLE_ENDPOINT=https://plausible.example.com
Omit to use Plausible’s default endpoint.

Complete example

# Database
DATABASE_URL=postgres://planningsup:mysecretpassword@localhost:5432/planningsup

# Server
PORT=20000
TRUSTED_ORIGINS=http://localhost:1420,http://localhost:4444,http://localhost:20000,http://tauri.localhost,tauri://localhost

# Auth (disabled in dev)
AUTH_ENABLED=false

# Jobs
RUN_JOBS=true
JOBS_QUIET_HOURS=21:00-06:00

Environment-specific notes

Docker Compose

Use env_file to load variables:
services:
  webapp:
    image: ghcr.io/kernoeb/planningsup
    env_file: webapp.env

Kubernetes

Use ConfigMaps and Secrets:
apiVersion: v1
kind: Secret
metadata:
  name: planningsup-secrets
type: Opaque
stringData:
  database-url: postgres://user:pass@postgres:5432/planningsup
  better-auth-secret: your-secret-key
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: planningsup-config
data:
  PORT: "20000"
  NODE_ENV: "production"
  AUTH_ENABLED: "true"
  RUN_JOBS: "true"

Systemd service

Use an environment file:
[Service]
EnvironmentFile=/etc/planningsup/env
ExecStart=/usr/local/bin/bun run start

Security best practices

Protect sensitive variables:
  • Never commit .env files to version control
  • Use strong, randomly generated secrets for BETTER_AUTH_SECRET and OPS_TOKEN
  • Rotate secrets regularly
  • Use read-only file permissions: chmod 600 .env
  • In CI/CD, use encrypted secrets storage
Recommended secret generation:
# Generate 32-byte random secret
openssl rand -base64 32

# Or use a UUID
uuidgen

Next steps

Self-hosting guide

Deploy PlanningSup on your own infrastructure

Architecture

Understand how PlanningSup components work together

Build docs developers (and LLMs) love