SaaSyBase
SaaSyBase

Deployment

This guide covers everything you need to take SaaSyBase from local development to production — whether you're deploying to Vercel, self-hosting on a VPS, or using a platform like Coolify.

Before Your First Deploy

Complete these steps after local development is finished and before you point real traffic at the app:

Warning

On platforms like Coolify, set all required production environment variables before the first deployment attempt. This app reads the database during npm run build to generate some pages, so missing or broken env vars can fail the build before the app ever starts.

Note

Quick rule for non-technical operators: managed platforms like Vercel and Coolify usually run npm install for you during the build, so those guides focus on the commands you still must think about yourself. Database seeding is different: it is a one-time bootstrap step for a brand-new database when you want the starter plans, settings, and editable site pages. It should not run automatically on every deploy.

Pre-flight checklist

1

Check Node.js Version

Pin your runtime to a supported Node.js version: ^20.19.0, ^22.12.0, or >=24.0.0. Check the exact version with node --version before the first deploy. Older versions like Node 18 will fail with modern Next.js and runtime API expectations.

2

Provision PostgreSQL

Create a hosted PostgreSQL database (e.g., Neon, Supabase, Railway) and update your DATABASE_URL environment variable.

3

Configure Environment Variables

Set all production env vars for your chosen auth provider, payment provider, email delivery, and server-side secrets.

4

Verify the production connection string

From the same environment that will run Prisma, confirm DATABASE_URL points at the intended PostgreSQL instance and that the credentials are valid. Do this before migrations so a bad connection string does not look like a Prisma or deployment failure.

5

Run Production Migrations

Apply your database schema to the new production database after DATABASE_URL is confirmed.

npm run prisma:deploy
6

Seed only if this is a brand-new database

Run the seed script one time if you want the starter admin, seeded plans, default settings, and editable site pages. Skip this on normal repeat deploys so you do not confuse setup with everyday releases.

npx prisma db seed
7

Configure Webhooks

Point your auth and payment provider webhooks to your new production domain and verify signatures are working.

8

Rotate Local Secrets

Generate new, secure random strings for ENCRYPTION_SECRET and other tokens. Never use your local development keys in production.

Warning

The shared Prisma migration history in this repo is PostgreSQL-only. Use PostgreSQL not just in production, but in any environment where you rely on npm run prisma:deploy or committed migrations.

PostgreSQL options

Any normal PostgreSQL connection string works with Prisma. You do not need a special vendor integration.

OptionGood fit whenDocs
NeonYou want a simple serverless Postgres defaultNeon docs
SupabaseYou want Postgres plus extra platform featuresSupabase docs
RailwayYou want one place for app plus database hostingRailway docs
RenderYou already deploy infrastructure on RenderRender docs
Self-hosted PostgreSQLYou want full control on your own machine or VPSPostgreSQL downloads

Common connection string shape:

DATABASE_URL="postgresql://USER:PASSWORD@HOST:5432/DBNAME?schema=public"

Tip

PostgreSQL is the cleanest path for local, staging, and production because it keeps every environment on the same committed migration lane.

Note

If you want help getting PostgreSQL running before deployment, read Local PostgreSQL. That guide is for local development and pre-production validation, not for choosing a production database host.

Required Environment Variables

Minimum production environment
# Core
DATABASE_URL="postgresql://..."
NEXT_PUBLIC_APP_URL="https://yourdomain.com"
NEXT_PUBLIC_APP_DOMAIN="yourdomain.com"
NEXT_PUBLIC_SITE_NAME="Your App"

# Auth (pick one)
AUTH_PROVIDER="betterauth"   # or "nextauth" or "clerk"

# Payment (pick one)
PAYMENT_PROVIDER="stripe"

# Security
ENCRYPTION_SECRET=""
INTERNAL_API_TOKEN=""
HEALTHCHECK_TOKEN=""
CRON_PROCESS_EXPIRY_TOKEN=""

# Email
EMAIL_PROVIDER="nodemailer"      # or "resend"
SMTP_HOST=""
SMTP_PORT=""
SMTP_USER=""
SMTP_PASS=""
EMAIL_FROM=""
SUPPORT_EMAIL=""

Note

For a complete list of all supported variables organized by group, see the Environment Variable Reference at the bottom of this page.

Tip

For Coolify and other self-hosted platforms, create these env vars in the platform UI before the first deploy instead of relying on a later shell session. The build itself needs a working DATABASE_URL, auth config, and server secrets.

Recommended secret setup

For most teams, the safest low-friction rule is: keep .env.localfor your laptop, and use your hosting platform's encrypted env vars in staging and production.

Standard secrets workflow

1

Use .env.local for development

Keep a local .env.local file on your laptop for rapid development and testing.

2

Set platform secrets

Set the real secrets in your platform env settings (Vercel, Coolify, etc.) first.

3

Optional: Centralize with a provider

If you want centralized secret management across platforms, opt into SECRETS_PROVIDER=infisical or SECRETS_PROVIDER=doppler. Install and authenticate the provider CLI in the real build/runtime environment first, then follow the dedicated Secrets & Providers guide for the provider-specific setup steps.

4

Verify environment

Run the smoke test to verify all required variables are present before your first deploy.

npm run secrets:smoke
5

Deploy

Deploy normally using your platform's standard migration, build, and start commands.

npm run prisma:deploy
npm run build
npm run start
Optional built-in provider envs
# Leave blank to use platform-native envs only
SECRETS_PROVIDER="infisical"

# Optional override when you need a custom export command
SECRETS_PROVIDER_COMMAND=""

# Provider-specific hints
INFISICAL_PROJECT_ID=""
INFISICAL_ENVIRONMENT=""

Before the first real deploy, you can also run npm run secrets:doctor to see the exact provider command, detected output shape, and which expected keys are present before the app boots.

Tip

Use the dedicated Secrets & Providers guide if you want the Infisical or Doppler bootstrap version instead of raw platform envs.

Note

Decision shortcut: use platform envs unless you already know you want one shared secret source across multiple environments. Choose Infisical or Doppler only when that centralization is worth the extra CLI/auth step.

Optional Sentry setup

SaaSyBase already keeps built-in operator logs in SystemLog and exposes them at /admin/logs. Sentry is optional and additive: when enabled, production logger events and React error boundaries also forward to Sentry.

Note

The smallest safe setup is server-only monitoring: set SENTRY_ENABLED="true", SENTRY_DSN, and SENTRY_ENVIRONMENT. Add NEXT_PUBLIC_SENTRY_DSN only if you also want browser crash reporting.
Minimal Sentry envs
# Server-side only
SENTRY_ENABLED="true"
SENTRY_CAPTURE_IN_DEVELOPMENT="false"
SENTRY_DSN="https://abc123@o000000.ingest.sentry.io/0000000"
SENTRY_ENVIRONMENT="production"
SENTRY_RELEASE="git-sha-or-image-tag"

# Optional browser crash reporting
NEXT_PUBLIC_SENTRY_DSN="https://abc123@o000000.ingest.sentry.io/0000000"

If you want to verify logger fan-out locally from the admin settings UI, set SENTRY_CAPTURE_IN_DEVELOPMENT="true" and use the Sentry smoke-test controls in /admin/settings.

Health Check

GET /api/health
Authorization: Bearer <HEALTHCHECK_TOKEN>

Returns database connectivity, environment validation, active auth/payment provider diagnostics, and runtime health. Without authorization, the endpoint returns a minimal public response — useful for uptime monitors that just need a 200 OK.

Use the authorized response immediately after a deploy and before pointing real traffic at the app. It is the fastest way to confirm the database, provider config, and runtime env all look correct from the deployed process.

In production, detailed health output requires a dedicated HEALTHCHECK_TOKEN.

Updating an existing live install

If your app is already live and customized, treat new official SaaSyBase releases as controlled upgrades instead of fresh installs. In most cases these releases should be normal maintenance: improvements, bug fixes, security fixes, and polish.

Note

The dedicated Updates & Upgrades guide explains the workflow in plain language for both technical and non-technical operators. It also makes clear that deeper tasks like Prisma changes only apply when a release actually includes them.
  • Read the release summary first so you know whether this is a routine update or one with infrastructure changes.
  • Merge and review the update in Git first, not on the production server.
  • Back up the live database and confirm the effective production env configuration before rollout.
  • Run the update in staging with production-like providers and storage before touching production.
  • Deploy production with the same ordered flow every time: npm run prisma:deploy, then build, then start or promote.

Vercel Deployment

Make sure the project uses a supported Node.js runtime in the Vercel project settings. Do not rely on older defaults such as Node 18.

Note

Vercel installs dependencies for you during the build. You do not add a separate manual npm install step in the Vercel guide unless you are debugging in a shell outside the normal Vercel build flow.

Vercel deployment steps

1

Import project to Vercel

Import your repository into Vercel. Vercel will automatically detect that it is a Next.js project.

2

Set environment variables

Add all your production environment variables in the Vercel project settings.

3

Deploy database schema

Run the Prisma deploy command against your production PostgreSQL database before the first live release.

npm run prisma:deploy
4

Seed once if the database is empty

Run the seed script one time against the same production database only if you want the starter records. This is not part of every Vercel deploy.

npx prisma db seed
5

Configure durable uploads when needed

If users or admins will upload files, configure S3-compatible storage by setting FILE_STORAGE="s3" and the related credentials. On Vercel, persistent app-managed uploads should be treated as required S3 storage because the local filesystem is not a durable production store.

6

Enable background jobs

Set CRON_SECRET to a secure random string. The cron endpoint also accepts CRON_PROCESS_EXPIRY_TOKEN or CRON_TOKEN, but CRON_SECRET is the simplest default for the bundled Vercel scheduler.

Deployment checklist

  • DATABASE_URL points at PostgreSQL
  • NEXT_PUBLIC_APP_URL matches the production domain exactly
  • AUTH_PROVIDER and PAYMENT_PROVIDER are set deliberately
  • You understand Vercel handles dependency install automatically during build
  • You ran npx prisma db seed only if this was a brand-new empty database
  • CRON_SECRET is configured for the bundled cron
  • FILE_STORAGE="s3" if you need durable uploads
  • Clerk and payment webhooks point at the production domain

Tip

The shipped vercel.json schedules the expiry cron once per day at 03:00 UTC. This is intentionally conservative so it works on Vercel Hobby plans. Increase frequency if your plan supports it. With the default schedule, subscription cleanup can lag by up to about 24 hours.

If you want Vercel to fetch secrets through the built-in bootstrap instead of native Vercel env vars, use the Secrets & Providers guide.

Optional Sentry on Vercel

Add the Sentry env vars in the Vercel project environment settings for Production and Preview. If you want browser crash capture, set both the server DSN and the public DSN.

Vercel env example
SENTRY_ENABLED="true"
SENTRY_DSN="https://abc123@o000000.ingest.sentry.io/0000000"
SENTRY_ENVIRONMENT="production"
SENTRY_RELEASE="vercel-${VERCEL_GIT_COMMIT_SHA}"
NEXT_PUBLIC_SENTRY_DSN="https://abc123@o000000.ingest.sentry.io/0000000"

Tip

Keep NEXT_PUBLIC_SENTRY_DSN blank if you only want server-side monitoring. That avoids shipping any browser Sentry config to clients.

Production webhooks

Point production webhook providers at your deployed domain:

IntegrationEndpointRequired secret
Clerk/api/webhooks/clerkCLERK_WEBHOOK_SECRET
Stripe/api/webhooks/payments or /api/webhooks/stripe or /api/stripe/webhookSTRIPE_WEBHOOK_SECRET
Paystack/api/webhooks/payments or /api/webhooks/paystackPAYSTACK_WEBHOOK_SECRET (optional, falls back to PAYSTACK_SECRET_KEY)
Paddle/api/webhooks/payments or /api/webhooks/paddlePADDLE_WEBHOOK_SECRET
Razorpay/api/webhooks/paymentsRAZORPAY_WEBHOOK_SECRET

Support ticket emails

If you want ticket activity to generate emails, set SUPPORT_EMAIL and make sure your email provider is configured. The support system can emit three admin/user email events:new_ticket_to_admin, admin_reply_to_user, and user_reply_to_admin.

Coolify Deployment

Coolify can deploy SaaSyBase as a standard Node/Next.js app without a custom Dockerfile:

Note

Pin the application runtime to Node.js ^20.19.0, ^22.12.0, or >=24.0.0 before the first deploy.

Note

In the normal Coolify Node or Nixpacks flow, dependency installation is handled by the platform image build. The steps below call out what you still need to configure explicitly: migrations, build, start, seed-once decisions, storage, and cron.

Coolify deployment steps

1

Connect repository

Connect your repository to Coolify as a standard Node or Nixpacks-style application.

2

Set environment variables and runtime

Add your production env vars in the Coolify application settings and pin the runtime to a supported Node.js version before the first deploy. At minimum, configure DATABASE_URL, NEXT_PUBLIC_APP_URL, NEXT_PUBLIC_APP_DOMAIN, NEXT_PUBLIC_SITE_NAME, AUTH_PROVIDER, PAYMENT_PROVIDER, ENCRYPTION_SECRET, INTERNAL_API_TOKEN, HEALTHCHECK_TOKEN, CRON_PROCESS_EXPIRY_TOKEN, and your email/provider secrets.

3

Use a build-safe PostgreSQL URL

If your DATABASE_URL includes a file-based CA path like sslrootcert=/etc/ssl/certs/coolify-ca.crt, the build container may fail if that file is not present there. Prefer a URL that also works in the build container unless you are deliberately shipping that certificate into both build and runtime images.

4

Configure a pre-deploy migration step

Use Coolify's deployment hooks or pre-deploy command field so every release applies migrations automatically before the app is started. A one-time manual run is fine for rescue work, but it is not enough for an ongoing production workflow.

npm run prisma:deploy
5

Seed once if this is the first launch of a new database

Run the seed script a single time if you want the starter admin, plans, settings, and site pages. Do not wire seeding into every deployment hook.

npx prisma db seed
6

Set build and start commands

Configure the exact commands Coolify should use after migrations succeed.

Build: npm run deploy:build
Start: npm run start
7

Configure production storage if uploads must persist

If the app will store user-managed uploads, use S3-compatible storage instead of the container filesystem so assets survive container rebuilds, restarts, and reschedules.

8

Configure background jobs

Create a scheduled HTTP job in Coolify to hit the expiry cron endpoint hourly or daily. The route accepts CRON_PROCESS_EXPIRY_TOKEN, CRON_SECRET, or CRON_TOKEN; pick one name and use it consistently.

curl -i -m 60 \
+  -H "Authorization: Bearer $CRON_PROCESS_EXPIRY_TOKEN" \
+  "https://yourdomain.com/api/cron/process-expiry"
9

Validate the deployed service before cutover

After deploy, call the authorized health endpoint and verify the app is running with the expected database, auth, payment, and env configuration before sending traffic to it.

If you want centralized secret loading here instead of raw Coolify env vars, see the Secrets & Providers guide.

Recommended Coolify commands
# Build command
npm run deploy:build

# Start command
npm run start

Tip

npm run deploy:build is the recommended Coolify build command for this repo because it applies committed migrations first and then runs the normal production build. Treat the migration hook, build command, and start command as one ordered deployment flow: migrate first, then build, then start.

Note

If you are handing this to a non-technical operator, give them a simple rule: deploys run migrations every time, but seeding happens only once for a fresh empty database.

Optional Sentry on Coolify

In Coolify, add the same env vars to the application service. Use a stable SENTRY_ENVIRONMENT value like staging or production so issues group cleanly.

Coolify env example
SENTRY_ENABLED="true"
SENTRY_DSN="https://abc123@o000000.ingest.sentry.io/0000000"
SENTRY_ENVIRONMENT="staging"
SENTRY_RELEASE="coolify-build-2026-04-22"
# Optional browser-side capture
NEXT_PUBLIC_SENTRY_DSN="https://abc123@o000000.ingest.sentry.io/0000000"

Linux VPS (Nginx / Apache)

Install and pin a supported Node.js runtime on the host before you build or start the app. Match the version policy in package.json.

Deployment flow

npm install
npm run secrets:smoke
npm run prisma:deploy
npm run build
npm run start

Run the app under systemd, pm2, or another process manager. systemd is the simplest default on most Linux VPS hosts.

Note

On a VPS, npm install is explicit because you manage the machine yourself. Add npx prisma db seed right after npm run prisma:deploy only on the first setup of an empty database.

Environment variable methods

Option 1 — systemd EnvironmentFile (recommended):

/etc/saasybase/app.env
HEALTHCHECK_TOKEN=<generated>
DATABASE_URL=postgresql://...
# ...other vars

Reference in your service unit:

systemd unit
[Service]
EnvironmentFile=/etc/saasybase/app.env
ExecStart=/usr/bin/npm run start
WorkingDirectory=/var/www/saasybase

Option 2 — dotenv alongside the app:

set -a; source .env.production; set +a
npm run start

If you want a VPS to fetch secrets from a centralized store instead of a local env file, see the Secrets & Providers guide.

Optional Sentry envs on a VPS:

/etc/saasybase/app.env
SENTRY_ENABLED=true
SENTRY_DSN=https://abc123@o000000.ingest.sentry.io/0000000
SENTRY_ENVIRONMENT=production
SENTRY_RELEASE=$(git rev-parse HEAD)
# Optional browser-side capture
NEXT_PUBLIC_SENTRY_DSN=https://abc123@o000000.ingest.sentry.io/0000000

If you use systemd, keep these alongside your other app env vars in the same environment file. If you deploy with Docker Compose or another process manager, pass the same values through that runtime instead.

Nginx reverse proxy

Nginx site configuration
server {
  server_name yourdomain.com www.yourdomain.com;

  location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection upgrade;
  }
}

Pair with TLS via Let's Encrypt or your existing certificate automation.

Apache reverse proxy

Apache VirtualHost
<VirtualHost *:80>
  ServerName yourdomain.com
  ServerAlias www.yourdomain.com
  ProxyPreserveHost On
  ProxyPass / http://127.0.0.1:3000/
  ProxyPassReverse / http://127.0.0.1:3000/
  RequestHeader set X-Forwarded-Proto "http"
</VirtualHost>

Enable the required proxy modules (proxy, proxy_http,headers) and terminate TLS in your HTTPS virtual host.

Cron job

curl -i -m 60         -H "Authorization: Bearer $CRON_PROCESS_EXPIRY_TOKEN"         "https://yourdomain.com/api/cron/process-expiry"

Schedule this to run hourly or daily depending on how quickly you need expired subscriptions to be cleaned up. If you standardize on a different alias, the route also accepts CRON_SECRET and CRON_TOKEN.

Deployment troubleshooting

  • If npm run prisma:deploy fails, verify DATABASE_URL from the same runtime context that will run the deploy. Most first-deploy Prisma errors are bad hostnames, wrong credentials, or the wrong database target.
  • If Prisma raises P3019, you are mixing provider lanes. In this repo the committed migration history is PostgreSQL, so do not try to deploy an old SQLite migration chain or SQLite database state into PostgreSQL.
  • If the app starts locally but not in production, use the authorized /api/health response to confirm provider config and required env vars before digging through platform logs.
  • If uploads appear to work and then disappear after a deploy or restart, move production storage to FILE_STORAGE="s3" with durable bucket credentials.
  • If cron-driven cleanup does not run, confirm the bearer token name matches one of the accepted aliases and test the endpoint manually before relying on the scheduler.
  • If webhooks stop after a deploy, verify the provider dashboard is pointing at the production domain and that the matching webhook secret env var was updated in the deployed environment.

Cron Jobs & Expiry Automation

curl -i -m 60         -H "Authorization: Bearer $CRON_PROCESS_EXPIRY_TOKEN"         "https://yourdomain.com/api/cron/process-expiry"

Run this periodically to:

  • Expire stale ACTIVE subscriptions past their expiresAt date.
  • Apply the configured organization-expiry policy to "zombie" organizations whose owner's subscription has lapsed. The shipped default is suspension rather than dismantling.
  • Process the subscription queue for batch operations.

The route accepts any of these tokens: CRON_PROCESS_EXPIRY_TOKEN, CRON_SECRET, or CRON_TOKEN. Unauthorized requests return 404 in production.

Lazy fallback

As a safety net, the dashboard layout checks for expired subscriptions and resets free tokens on every visit. The cron job is still recommended for timely cleanup, but stale data won't persist indefinitely even if the cron fails.

File Storage (S3)

By default, uploaded files are stored on the local filesystem. Switch to S3 for production:

.env.local
FILE_STORAGE="s3"
FILE_S3_BUCKET="my-bucket-name"
AWS_REGION=""
AWS_ACCESS_KEY_ID=""
AWS_SECRET_ACCESS_KEY=""
FILE_CDN_DOMAIN=""        # Optional: CloudFront domain
FILE_S3_ENDPOINT=""       # Optional: S3-compatible endpoint (R2, MinIO, etc.)

When FILE_CDN_DOMAIN is set, uploads return CDN URLs instead of raw S3 links. Set FILE_S3_ENDPOINTto your provider's endpoint for S3-compatible services (Cloudflare R2, DigitalOcean Spaces, MinIO). Leave it blank for standard AWS S3.

Note

The runtime still accepts the older LOGO_STORAGE, LOGO_S3_BUCKET, LOGO_S3_ENDPOINT, and LOGO_CDN_DOMAINvariables as legacy aliases.

S3 CORS for browser uploads

Bucket CORS policy
[
  {
    "AllowedHeaders": ["*"],
    "AllowedMethods": ["GET", "PUT", "POST", "HEAD"],
    "AllowedOrigins": ["https://yourdomain.com"],
    "ExposeHeaders": ["ETag"],
    "MaxAgeSeconds": 3000
  }
]

Without a browser-friendly CORS policy, admin uploads can fail even when the bucket credentials are valid.

CloudFront or CDN fronting

For AWS-hosted setups, front the bucket with CloudFront and use:

  • Response headers policy: CORS-With-Preflight
  • Origin request policy: CORS-S3Origin
  • Cache policy: CachingOptimized
  • Allowed methods: GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE

Also add your storage/CDN hostnames to next.config.mjs image remote patterns so branded images render correctly.

Demo Read-Only Mode

.env
DEMO_READ_ONLY_MODE="true"
      DEMO_READ_ONLY_EXEMPT_USER_IDS="user_123,user_456"
      DEMO_READ_ONLY_EXEMPT_EMAILS="owner@example.com"

When enabled, all write operations (POST, PUT, PATCH, DELETE) to /api/* are blocked with a 403 response. Auth and webhook callbacks are exempted so sign-in still works.

Use this for sharing a safe, explorable demo. A read-only modal appears in admin/dashboard, and blocked actions trigger an informational toast.

For a narrow operator bypass, allowlist exact internal user IDs or exact emails with DEMO_READ_ONLY_EXEMPT_USER_IDS and DEMO_READ_ONLY_EXEMPT_EMAILS. Prefer user IDs when possible because they are stable and avoid ambiguity if a user later changes email.

Environment Variable Reference

A complete list organized by group:

GroupKey prefix / variablesNotes
DatabaseDATABASE_URLPoints Prisma at the target database. The committed provider lane in this repo is PostgreSQL.
AppNEXT_PUBLIC_APP_URL, NEXT_PUBLIC_SITE_NAME, NEXT_PUBLIC_APP_DOMAINPublic-facing URL and branding
BrandingNEXT_PUBLIC_SITE_LOGO, NEXT_PUBLIC_SITE_LOGO_LIGHT/DARKSite logo configuration
AuthAUTH_PROVIDER, CLERK_*, BETTER_AUTH_URL, NEXT_PUBLIC_BETTER_AUTH_URL, BETTER_AUTH_SECRET, AUTH_SECRET, NEXTAUTH_SECRETChoose Clerk, Better Auth, or NextAuth
Auth OAuthGITHUB_CLIENT_ID/SECRET, GOOGLE_CLIENT_ID/SECRETOAuth providers for the self-hosted auth lanes
PaymentPAYMENT_PROVIDER, STRIPE_*, PAYSTACK_*, PADDLE_*, RAZORPAY_*Choose provider
Payment configPAYMENT_AUTO_CREATE, PAYMENTS_CURRENCYCatalog sync and currency
CurrencyDEFAULT_CURRENCY, PADDLE_CURRENCY, PAYSTACK_CURRENCY, RAZORPAY_CURRENCYCurrency resolution chain
EmailEMAIL_PROVIDER, SMTP_*, RESEND_API_KEY, EMAIL_FROM, SUPPORT_EMAILEmail delivery
GeolocationIPINFO_LITE_TOKENOptional; session geolocation
StorageFILE_STORAGE, FILE_S3_BUCKET, FILE_S3_ENDPOINT, AWS_*, FILE_CDN_DOMAINFile storage (legacy LOGO_* aliases still work)
AnalyticsTRAFFIC_ANALYTICS_PROVIDER, NEXT_PUBLIC_GA_MEASUREMENT_ID, GA_*, POSTHOG_*Traffic analytics provider configuration
SecurityENCRYPTION_SECRET, INTERNAL_API_TOKEN, HEALTHCHECK_TOKEN, CRON_*Server-side secrets
DemoDEMO_READ_ONLY_MODERead-only demo mode
Dev helpersALLOW_UNSIGNED_CLERK_WEBHOOKS, ALLOW_SYNC_IN_PRODBreak-glass local/dev helpers only