Operations
Environment and Configuration
Required environment variables for Bunship web + API runtime.
This page is the source of truth for required env vars in the current repo.
Code references:
- web schema:
apps/ship/src/env.ts - auth runtime:
packages/auth/src/server.ts,packages/auth-clerk/src/server.ts - api runtime:
apps/ship-api/src/server.tsandapps/ship-api/src/index.ts
Minimum Required (Web + API)
Without these variables, startup/build will fail or core auth/payment/storage flows will break.
| Variable | Required | Used by | Notes |
|---|---|---|---|
NEXT_PUBLIC_AUTH_PROVIDER | Yes (default better-auth) | web, api | better-auth or clerk |
DATABASE_URL | Yes | web, api, auth | Postgres DSN |
NEXT_PUBLIC_SITE_URL | Yes | web, api, auth | Site origin, supports comma-separated origins |
NEXT_PUBLIC_SERVER_URL | Yes | web, api, auth | API origin |
NEXT_PUBLIC_API_PREFIX | No (default /api/v1) | web, api, auth | API route prefix |
ADMIN_EMAIL_LIST | Yes | web, auth | Comma-separated admin emails |
EMAIL_FROM | Yes | auth | Sender for verification/reset/OTP emails |
RESEND_API_KEY | Yes | web/auth | Email provider key |
S3_ENDPOINT | Yes | web, api | Storage endpoint |
S3_REGION | Yes | web, api | Storage region |
S3_ACCESS_KEY | Yes | web, api | Storage access key |
S3_SECRET_KEY | Yes | web, api | Storage secret |
S3_BUCKET | Yes | web, api | Bucket name |
NEXT_PUBLIC_S3_URL_BASE | Yes | web, api | Public object URL base |
STRIPE_SECRET_KEY | Yes | web, api | Stripe API key |
STRIPE_WEBHOOK_SECRET | Yes | web, api | Stripe webhook signature secret |
S_GITHUB_PERSONAL_ACCESS_TOKEN | Yes | web, api | GitHub API access in admin/features |
CLOUDFLARE_ACCOUNT_ID | Yes (in web schema) | web | Required by current env validator |
Better Auth only (when NEXT_PUBLIC_AUTH_PROVIDER=better-auth)
| Variable | Required | Used by | Notes |
|---|---|---|---|
BETTER_AUTH_SECRET | Yes | auth/api | Better Auth signing secret |
BETTER_AUTH_URL | Yes | auth/api | Auth base URL |
AUTH_SECRET | Yes | web/auth | Required by web env schema |
OAUTH_GITHUB_CLIENT_ID | Yes (if GitHub OAuth enabled) | web/auth | GitHub OAuth |
OAUTH_GITHUB_CLIENT_SECRET | Yes (if GitHub OAuth enabled) | web/auth | GitHub OAuth |
OAUTH_GOOGLE_CLIENT_ID | Recommended | auth | Google OAuth server client ID |
OAUTH_GOOGLE_CLIENT_SECRET | Recommended | auth | Google OAuth server secret |
NEXT_PUBLIC_OAUTH_GOOGLE_CLIENT_ID | Yes (if Google OAuth enabled) | web | Google One Tap / Sign-In UI |
Clerk only (when NEXT_PUBLIC_AUTH_PROVIDER=clerk)
| Variable | Required | Used by | Notes |
|---|---|---|---|
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY | Yes | web | Clerk public key |
CLERK_SECRET_KEY | Yes | api/auth | Clerk server key |
CLERK_WEBHOOK_SECRET | Yes | api | Used by /api/v1/webhook/clerk |
API Runtime / Deployment Variables
| Variable | Required | Notes |
|---|---|---|
PORT | No (default 9001) | API listen port |
APP_ENV | Recommended | development / production style env flag |
NODE_ENV | Recommended | Node runtime env |
JWT_SECRET | Recommended | API JWT signing secret (fallback exists but not safe for production) |
JWT_EXPIRATION | No (default 7d) | API JWT TTL |
GIT_COMMIT_SHA | No | Build metadata for logs |
BUILD_TIME | No | Build metadata for logs |
CROSS_SUB_DOMAIN | Optional | Cross-subdomain cookie domain |
Optional Feature Variables
| Variable | Feature |
|---|---|
UPSTASH_REDIS_REST_URL, UPSTASH_REDIS_REST_TOKEN | KV/Redis features |
NEXT_PUBLIC_GA_ID, NEXT_PUBLIC_UMAMI_DATA_ID | Analytics |
NEXT_PUBLIC_APP_VERSION, VERCEL_GIT_COMMIT_SHA | UI version display |
BETTER_UPLOAD_PROVIDER, AWS_FORCE_PATH_STYLE | Upload provider behavior |
OPENAI_API_KEY, OPENAI_API_BASE | Admin AI command/copilot |
REPLICATE_API_TOKEN | Replicate provider |
KIE_API_KEY, KIE_API_BASE_URL | KIE provider |
FAL_API_KEY | FAL provider |
Local .env Example (Better Auth)
NEXT_PUBLIC_AUTH_PROVIDER=better-auth
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/bunship
BETTER_AUTH_SECRET=replace-with-long-random-secret
BETTER_AUTH_URL=http://localhost:3001
AUTH_SECRET=replace-with-long-random-secret
NEXT_PUBLIC_SITE_URL=http://localhost:3000
NEXT_PUBLIC_SERVER_URL=http://localhost:3001
NEXT_PUBLIC_API_PREFIX=/api/v1
ADMIN_EMAIL_LIST=admin@example.com
EMAIL_FROM=Bunship <noreply@example.com>
RESEND_API_KEY=re_xxx
OAUTH_GITHUB_CLIENT_ID=xxx
OAUTH_GITHUB_CLIENT_SECRET=xxx
OAUTH_GOOGLE_CLIENT_ID=xxx
OAUTH_GOOGLE_CLIENT_SECRET=xxx
NEXT_PUBLIC_OAUTH_GOOGLE_CLIENT_ID=xxx
S3_ENDPOINT=https://s3.example.com
S3_REGION=auto
S3_ACCESS_KEY=xxx
S3_SECRET_KEY=xxx
S3_BUCKET=bunship
NEXT_PUBLIC_S3_URL_BASE=https://cdn.example.com
STRIPE_SECRET_KEY=sk_test_xxx
STRIPE_WEBHOOK_SECRET=whsec_xxx
S_GITHUB_PERSONAL_ACCESS_TOKEN=ghp_xxx
CLOUDFLARE_ACCOUNT_ID=xxxLocal .env Example (Clerk)
NEXT_PUBLIC_AUTH_PROVIDER=clerk
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/bunship
NEXT_PUBLIC_SITE_URL=http://localhost:3000
NEXT_PUBLIC_SERVER_URL=http://localhost:3001
NEXT_PUBLIC_API_PREFIX=/api/v1
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_xxx
CLERK_SECRET_KEY=sk_test_xxx
CLERK_WEBHOOK_SECRET=whsec_xxx
ADMIN_EMAIL_LIST=admin@example.com
EMAIL_FROM=Bunship <noreply@example.com>
RESEND_API_KEY=re_xxx
S3_ENDPOINT=https://s3.example.com
S3_REGION=auto
S3_ACCESS_KEY=xxx
S3_SECRET_KEY=xxx
S3_BUCKET=bunship
NEXT_PUBLIC_S3_URL_BASE=https://cdn.example.com
STRIPE_SECRET_KEY=sk_test_xxx
STRIPE_WEBHOOK_SECRET=whsec_xxx
S_GITHUB_PERSONAL_ACCESS_TOKEN=ghp_xxx
CLOUDFLARE_ACCOUNT_ID=xxx