Environment
Root .env keys shared by marketing and docs.
All apps load env from the repository root (.env / .env.example). Copy .env.example to .env and fill values. Turbo exposes the public URL keys via globalEnv.
Public URLs
| Key | Local default | Used by |
|---|---|---|
NEXT_PUBLIC_APP_URL | http://localhost:3001 | Leftover package CORS / auth origins (point at marketing) |
NEXT_PUBLIC_SAAS_URL | http://localhost:3001 | Same as app URL now that the dashboard app is gone |
NEXT_PUBLIC_MARKETING_URL | http://localhost:3001 | Landing, legal, API, checkout |
NEXT_PUBLIC_DOCS_URL | http://localhost:3002 | This docs site |
NODE_ENV in .env is development for local work. Production builds set NODE_ENV=production in the app build script before dotenv so Next does not inherit development from .env.
Database
| Key | Notes |
|---|---|
DATABASE_URL | Prisma (pooled) |
DIRECT_URL | Prisma migrate / introspect |
POSTGRES_PORT | Docker Compose host port |
Setup walkthrough: Database.
Auth
| Key | Notes |
|---|---|
BETTER_AUTH_SECRET | At least 32 characters |
BETTER_AUTH_URL | Better Auth base URL |
GOOGLE_CLIENT_ID | Google OAuth (required) |
GOOGLE_CLIENT_SECRET | Google OAuth (required) |
GITHUB_CLIENT_ID | GitHub OAuth (optional) |
GITHUB_CLIENT_SECRET | GitHub OAuth (optional) |
APPLE_CLIENT_ID | Apple Sign In Service ID (optional) |
APPLE_TEAM_ID | Apple Team ID (optional) |
APPLE_KEY_ID | Apple Key ID (optional) |
APPLE_PRIVATE_KEY | Apple .p8 private key; use \n for newlines (optional) |
Payments and email
| Key | Notes |
|---|---|
MAYAR_API_KEY | Mayar dashboard API key |
MAYAR_WEBHOOK_SECRET | Shared secret for {MARKETING_URL}/api/webhooks/mayar |
MAYAR_PRODUCT_ID_SOLO | Mayar payment-link product ID for Solo |
MAYAR_PRODUCT_ID_PRO | Mayar payment-link product ID for Pro |
MAYAR_PAYMENT_LINK_SOLO | Hosted checkout URL for Solo |
MAYAR_PAYMENT_LINK_PRO | Hosted checkout URL for Pro |
RESEND_KEY | Transactional email — see Resend |
RESEND_EMAIL_DOMAIN | From address (local default [email protected]) — see Mail |
Setup walkthrough: Payments, Storefront checkout, and Mail.
Optional
| Key | Notes |
|---|---|
NEXT_PUBLIC_ENABLE_SENTRY | Sentry feature flag (false disables) — see Monitoring |
NEXT_PUBLIC_SENTRY_DSN | Sentry DSN (empty disables) — see Sentry |
SENTRY_AUTH_TOKEN | Optional. Source map uploads during build — see Sentry |
NEXT_PUBLIC_ENABLE_POSTHOG | PostHog feature flag (false disables) — see Analytics |
NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN | PostHog project token (empty disables) — see PostHog |
NEXT_PUBLIC_POSTHOG_HOST | PostHog API host (default https://us.i.posthog.com; EU: https://eu.i.posthog.com) |
AI_GATEWAY_API_KEY | Vercel AI Gateway key for @repo/ai chat — see AI |
OPENAI_API_KEY | Reserved for direct OpenAI usage |
SMTP_HOST / SMTP_PORT | Local SMTP (Mailpit) — see Mailpit; not wired into sendEmail yet |
SMTP_USER / SMTP_PASS | Optional SMTP auth for Nodemailer |
MAILPIT_URL | Mailpit web UI (default http://localhost:8025) |
S3_REGION | R2 region (usually auto) |
S3_BUCKET | R2 bucket name |
S3_ENDPOINT | https://<ACCOUNT_ID>.r2.cloudflarestorage.com |
S3_ACCESS_KEY_ID | R2 API token access key |
S3_SECRET_ACCESS_KEY | R2 API token secret |
S3_PUBLIC_URL | Optional public base (https://pub-….r2.dev or custom domain) for /api/storage/public |
Cloudflare R2 setup
Full walkthrough: Storage and Cloudflare R2.
- Create a private R2 bucket and an API token with Object Read & Write.
- Set CORS on the bucket so browsers can
PUT/GETfrom your marketing origin (NEXT_PUBLIC_MARKETING_URL), e.g. allowPUT,GET,HEADandContent-Type. - Keep the bucket private; use short-lived signed URLs from
/api/storage. Only setS3_PUBLIC_URLif you intentionally expose objects via r2.dev or a custom domain.
Validated in packages/env (envSchema server-side, clientEnvSchema for NEXT_PUBLIC_* used in the browser).