Environments
Environment variables required by each app, validation schemas, and file conventions.
Overview
Environment variables are validated at startup using t3-oss/env with Zod schemas. If a required variable is missing or malformed, the app fails immediately with a clear error.
Shared schemas (auth, stripe, supabase) are defined in their respective packages and composed into app-level schemas via the extends property.
Prefix conventions
| Framework | Client prefix | Example |
|---|---|---|
| Vite (App, Editor, Player) | VITE_ | VITE_SUPABASE_URL |
| Next.js (Web) | NEXT_PUBLIC_ | NEXT_PUBLIC_BASE_URL |
| Server (API) | (none) | DATABASE_URL |
Only prefixed variables are exposed to the browser. Server-side variables without a prefix stay on the server.
Build-time vs runtime
Variables behave differently depending on how the app is built:
- Build-time (inlined):
VITE_*andNEXT_PUBLIC_*variables are replaced with their values during the build step. They are baked into the JavaScript bundle and cannot be changed after build. This applies to all static apps (App, Editor, Player, Web). - Runtime (server): Variables without a prefix are read from the
.envfile when the server process starts. They can be changed by editing the file and restarting the container. This applies to Docker-based apps (API, Docs).
API (apps/api)
All variables are runtime — read from .env on the server when the container starts. The file must be created manually on the production server at /home/www/api/.env.
| Variable | Required | Phase | Description |
|---|---|---|---|
DATABASE_URL | Yes | Runtime | PostgreSQL connection string |
SUPABASE_URL | Yes | Runtime | Supabase REST API URL |
SUPABASE_SERVICE_ROLE_KEY | Yes | Runtime | Supabase service role key (admin access) |
CLERK_SECRET_KEY | Yes | Runtime | Clerk backend secret key |
API_KEY | Yes | Runtime | API key for service-to-service authentication |
PORT | No | Runtime | Server port (default: 3001) |
CLERK_WEBHOOK_SECRET | No | Runtime | Clerk webhook signing secret — webhook routes disabled when not set |
RESEND_API_KEY | No | Runtime | Resend API key — transactional emails disabled when not set |
Template: apps/api/.env.local
App (apps/app)
All variables are build-time (VITE_ prefixed) — inlined into the bundle during pnpm build:app. Extends shared schemas from @workspace/auth, @workspace/stripe, and @workspace/database.
Core
| Variable | Required | Phase | Description |
|---|---|---|---|
VITE_SUPABASE_URL | Yes | Build | Supabase project URL |
VITE_SUPABASE_ANON_KEY | Yes | Build | Supabase anonymous (public) key |
VITE_AUTH_PUBLISHABLE_KEY | Yes | Build | Clerk publishable key (starts with pk_) |
App-specific
| Variable | Required | Phase | Description |
|---|---|---|---|
VITE_USE_LOCAL_API | No | Build | Local API mode: "dev", "seed", or unset for remote |
VITE_API_BASE_URL | No | Build | API base URL override |
VITE_FLAGS | No | Build | Feature flags: comma-separated list or "*" for all |
VITE_WEB_BASE_URL | No | Build | Marketing site URL (default: https://bridge-training.com) |
VITE_PLAYER_BASE_URL | No | Build | Deal player URL |
VITE_E2E | No | Build | Set to "true" to enable E2E testing mode |
VITE_SUPPORT_EMAIL | No | Build | Support email displayed in UI |
Stripe donation links
| Variable | Required | Phase | Description |
|---|---|---|---|
VITE_STRIPE_DONATE_ONETIME_3 | No | Build | One-time 3€ donation link |
VITE_STRIPE_DONATE_ONETIME_5 | No | Build | One-time 5€ donation link |
VITE_STRIPE_DONATE_ONETIME_10 | No | Build | One-time 10€ donation link |
VITE_STRIPE_DONATE_ONETIME_20 | No | Build | One-time 20€ donation link |
VITE_STRIPE_DONATE_ONETIME_50 | No | Build | One-time 50€ donation link |
VITE_STRIPE_DONATE_ONETIME_CUSTOM | No | Build | Custom amount donation link |
VITE_STRIPE_DONATE_MONTHLY_2 | No | Build | Monthly 2€ donation link |
VITE_STRIPE_DONATE_MONTHLY_5 | No | Build | Monthly 5€ donation link |
VITE_STRIPE_DONATE_MONTHLY_10 | No | Build | Monthly 10€ donation link |
VITE_STRIPE_DONATE_MONTHLY_15 | No | Build | Monthly 15€ donation link |
VITE_STRIPE_BILLING_PORTAL_URL | No | Build | Stripe billing portal for subscription management |
Template: apps/app/.env.example
Editor (apps/editor)
All variables are build-time (VITE_ prefixed) — inlined into the bundle during build.
| Variable | Required | Phase | Description |
|---|---|---|---|
VITE_DEAL_GENERATION_ENDPOINT | Yes | Build | URL for deal generation/shortening service |
VITE_PLAYER_BASE_URL | Yes | Build | Base URL for the deal player |
VITE_SUPPORT_EMAIL | No | Build | Support email (default: contact@bridge-training.com) |
Template: apps/editor/.env.development
Web (apps/web)
All variables are build-time (NEXT_PUBLIC_ prefixed) — inlined during next build.
| Variable | Required | Phase | Description |
|---|---|---|---|
NEXT_PUBLIC_BASE_URL | No | Build | Site base URL for sitemap and OG tags |
NEXT_PUBLIC_SIGN_IN_URL | No | Build | Sign-in page URL |
NEXT_PUBLIC_SIGN_UP_URL | No | Build | Sign-up page URL |
NEXT_PUBLIC_EDITOR_URL | No | Build | Editor app URL |
NEXT_PUBLIC_STRIPE_DONATE_ONETIME_* | No | Build | Same Stripe links as App, with NEXT_PUBLIC_ prefix |
NEXT_PUBLIC_STRIPE_DONATE_MONTHLY_* | No | Build | Same Stripe links as App, with NEXT_PUBLIC_ prefix |
NEXT_PUBLIC_STRIPE_BILLING_PORTAL_URL | No | Build | Stripe billing portal |
Template: apps/web/.env.example
Database (packages/database)
Used by Drizzle Kit and Supabase CLI for migrations and local development.
| Variable | Required | Phase | Description |
|---|---|---|---|
DATABASE_URL | Yes | Runtime | PostgreSQL connection string |
SUPABASE_WORKDIR | No | Runtime | Supabase CLI working directory (default: ./supabase) |
SUPABASE_PROJECT_ID_PROD | No | Runtime | Production project ID (for remote operations) |
SUPABASE_DB_URL_PROD | No | Runtime | Production database URL (for remote migrations) |
Template: packages/database/.env.local.example
CLI (packages/cli)
Internal CLI tool for admin operations.
| Variable | Required | Phase | Description |
|---|---|---|---|
DATABASE_URL | Yes | Runtime | PostgreSQL connection string |
CLERK_SECRET_KEY | Yes | Runtime | Clerk backend secret key |
Template: packages/cli/.env.example
Deploy (/.env.deploy)
Used by release scripts only. See Deployment for details.
| Variable | Required | Phase | Description |
|---|---|---|---|
API_HOST | Yes | Deploy | SSH host alias for API server |
API_REMOTE_DIR | Yes | Deploy | Remote directory for API deployment |
API_PORT | Yes | Deploy | API container exposed port |
API_IMAGE | Yes | Deploy | Docker image name for API |
DOCS_HOST | Yes | Deploy | SSH host alias for Docs server |
DOCS_REMOTE_DIR | Yes | Deploy | Remote directory for Docs deployment |
DOCS_PORT | Yes | Deploy | Docs container exposed port |
DOCS_IMAGE | Yes | Deploy | Docker image name for Docs |
API_URL | No | Deploy | API URL (displayed after release) |
DOCS_URL | No | Deploy | Docs URL (displayed after release) |
Override locally with .env.deploy.local (gitignored).
Validation schemas
Schemas are colocated with the packages that own the concern:
| Schema | Package | Used by |
|---|---|---|
authEnv | packages/auth/src/env.ts | App |
stripeEnv | packages/stripe/src/env.ts | App |
stripeEnvNextjs | packages/stripe/src/env-nextjs.ts | Web |
supabaseEnv | packages/database/src/env.ts | App |
| API env | apps/api/src/lib/env.ts | API |
| Editor env | apps/editor/src/lib/env.ts | Editor |
| Web env | apps/web/src/lib/env.ts | Web |
| App env | apps/app/src/lib/env.ts | App |