Documentation
Environment Variables
Required and optional environment variables for Motoko Base — database, auth, billing, email, storage, analytics, monitoring, and AI.
Motoko Base reads configuration from environment variables. Copy .env.example to .env or .env.local and fill in values:
cp .env.example .envNever commit real secrets. .env* is gitignored except .env.example. Never put server-only secrets on NEXT_PUBLIC_* — those are exposed to the browser.
Optional integrations soft-fail when unset: the app boots, unrelated routes keep working, and feature pages show a clear configuration message instead of crashing.
Required
These three variables are enough to start the dev server and run migrations:
| Variable | Required | Purpose |
|---|---|---|
DATABASE_URL | Yes | PostgreSQL connection string (server-only) |
BETTER_AUTH_SECRET | Yes | Signing secret for sessions and tokens |
BETTER_AUTH_URL | Yes | Public origin for auth callbacks — use http://localhost:3000 locally |
Generate a secret:
openssl rand -base64 32Strongly recommended
Email verification is required before dashboard access. Without Resend configured, you can start the app but you will not receive verification emails after sign-up.
| Variable | Required | Purpose |
|---|---|---|
RESEND_API_KEY | Recommended | Resend API key for transactional email |
EMAIL_FROM | Recommended | Sender address, e.g. Motoko Base <onboarding@resend.dev> for Resend onboarding tests |
Application
| Variable | Required | Purpose |
|---|---|---|
NEXT_PUBLIC_APP_URL | No | Public app origin for short links (/r/{slug}) and password-reset redirects. Falls back to the request origin when unset. Keep aligned with BETTER_AUTH_URL in production. |
Authentication
| Variable | Required | Purpose |
|---|---|---|
BETTER_AUTH_SECRET | Yes | Session and token signing secret |
BETTER_AUTH_URL | Yes | Canonical auth origin (must match the URL users hit for callbacks) |
BETTER_AUTH_TRUSTED_ORIGINS | No | Comma-separated extra origins for preview/staging hosts |
GOOGLE_CLIENT_ID | No | Google OAuth client ID — leave unset to disable Google sign-in |
GOOGLE_CLIENT_SECRET | No | Google OAuth client secret |
GITHUB_CLIENT_ID | No | GitHub OAuth app client ID — leave unset to disable GitHub sign-in |
GITHUB_CLIENT_SECRET | No | GitHub OAuth app client secret |
OAuth callback URLs must match BETTER_AUTH_URL:
- Google:
{BETTER_AUTH_URL}/api/auth/callback/google - GitHub:
{BETTER_AUTH_URL}/api/auth/callback/github
Database
| Variable | Required | Purpose |
|---|---|---|
DATABASE_URL | Yes | PostgreSQL connection string (Supabase or local). Never NEXT_PUBLIC_*. |
For Supabase at runtime, prefer the transaction pooler (often port 6543). If migrations fail through the pooler, temporarily point DATABASE_URL at the direct connection (often port 5432). See src/lib/db/README.md.
Billing
| Variable | Required | Purpose |
|---|---|---|
BILLING_PROVIDER | No | Billing provider selection (polar in v1). Defaults to polar. |
POLAR_ACCESS_TOKEN | No | Polar Organization Access Token — leave unset to stay on Free |
POLAR_WEBHOOK_SECRET | No | Webhook secret from Polar → Settings → Webhooks |
POLAR_PRO_MONTHLY_PRODUCT_ID | No | Pro monthly product ID from Polar Dashboard |
POLAR_PRO_YEARLY_PRODUCT_ID | No | Pro yearly product ID (optional) |
POLAR_GROWTH_MONTHLY_PRODUCT_ID | No | Growth monthly product ID (optional) |
POLAR_GROWTH_YEARLY_PRODUCT_ID | No | Growth yearly product ID (optional) |
POLAR_SCALE_MONTHLY_PRODUCT_ID | No | Scale monthly product ID (optional) |
POLAR_SCALE_YEARLY_PRODUCT_ID | No | Scale yearly product ID (optional) |
POLAR_SERVER | No | sandbox or production (tokens and products are environment-specific) |
Use the {PLAN}_{MONTHLY|YEARLY}_PRODUCT_ID pattern as the canonical names (matching .env.example). Legacy aliases such as POLAR_PRO_PRODUCT_ID remain supported at runtime for backward compatibility — see comments in .env.example and src/lib/billing/providers/polar/product-map.ts.
Webhook endpoint: {APP_URL}/api/billing/webhooks/polar
| Variable | Required | Purpose |
|---|---|---|
RESEND_API_KEY | No* | Resend API key (server-only) |
EMAIL_FROM | No* | Single sender identity, e.g. Motoko Base <noreply@yourdomain.com> |
* Both are needed for email delivery. The app boots without them, but signup verification will not work.
Storage
Cloudflare R2 powers the File Storage demo and avatar uploads. Leave unset to boot without Storage.
| Variable | Required | Purpose |
|---|---|---|
R2_ACCOUNT_ID | No | Cloudflare account ID (used to build the S3 API endpoint) |
R2_ACCESS_KEY_ID | No | R2 API token access key |
R2_SECRET_ACCESS_KEY | No | R2 API token secret |
R2_BUCKET_NAME | No | Private bucket name. A slash is treated as an object-key prefix: my-bucket/demo → bucket my-bucket, prefix demo/ |
R2_PREFIX | No | Optional explicit object-key prefix (overrides a slash suffix on the bucket name) |
R2_ENDPOINT | No | Optional S3 API endpoint override (defaults from R2_ACCOUNT_ID) |
Analytics
PostHog is split into client capture (project token) and server HogQL queries (personal API key).
| Variable | Required | Purpose |
|---|---|---|
NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN | No | PostHog project API key for client capture |
NEXT_PUBLIC_POSTHOG_HOST | No | Ingest host (US default: https://us.i.posthog.com, EU: https://eu.i.posthog.com) |
POSTHOG_PERSONAL_API_KEY | No | Personal API key with Query Read — used by /dashboard/analytics |
POSTHOG_PROJECT_ID | No | PostHog project ID for HogQL queries |
POSTHOG_HOST | No | App API host for Query API (US: https://us.posthog.com, EU: https://eu.posthog.com) |
Monitoring
| Variable | Required | Purpose |
|---|---|---|
NEXT_PUBLIC_SENTRY_DSN | No | Public Sentry DSN — leave unset to disable monitoring |
SENTRY_AUTH_TOKEN | No | Auth token for source map upload during next build |
SENTRY_ORG | No | Sentry organization slug |
SENTRY_PROJECT | No | Sentry project slug |
Sentry is also disabled automatically during next dev (even if DSN is set) to avoid webpack listener noise.
AI
| Variable | Required | Purpose |
|---|---|---|
OPENAI_API_KEY | No | OpenAI or compatible API key — leave unset to disable AI Email demo |
OPENAI_BASE_URL | No | Optional OpenAI-compatible API base URL |
OPENAI_MODEL | No | Model ID (defaults to gpt-4o-mini) |
Quick reference by boot requirement
| Category | Minimal boot | Full feature set |
|---|---|---|
| Database | DATABASE_URL | DATABASE_URL |
| Authentication | BETTER_AUTH_SECRET, BETTER_AUTH_URL | + optional OAuth vars |
| — | RESEND_API_KEY, EMAIL_FROM | |
| Billing | — | POLAR_* vars |
| Storage | — | R2_* vars |
| Analytics | — | PostHog vars |
| Monitoring | — | Sentry vars |
| AI | — | OPENAI_API_KEY |
See .env.example for inline comments on every variable.
Next steps
Configuration — Where config files live and how to change navigation, billing plans, metadata, and integrations.