Environment Variables
The repo uses separate environment files for the product app, marketing site, documentation site, and Convex backend.
The repo uses separate environment files for the product app, marketing site, documentation site, and Convex backend.
apps/app/.env
apps/marketing/.env
apps/docs/.env
packages/backend/.envEach workspace has an .env.example file. Copy those examples during setup and
fill only the integrations you plan to use.
Runtime Boundary
Next.js apps read their local .env files at build and runtime.
packages/config/src/brand.ts contains static browser-safe product identity.
Customize that source file for the product name, labels, logo alt text, GitHub
URL, support email, and default copy. Runtime URLs remain in the environment
schema of the deployable that owns them.
Convex functions do not read packages/backend/.env after deployment. Backend
variables must also be set in the Convex dashboard or with the Convex CLI:
bun --cwd packages/backend convex env set NAME "value"Keep local .env files out of git.
Product App
File: apps/app/.env
Required:
NEXT_PUBLIC_CONVEX_URL=
NEXT_PUBLIC_CONVEX_SITE_URL=
NEXT_PUBLIC_APP_URL=http://localhost:3000Optional:
NEXT_PUBLIC_DOCS_URL=http://localhost:3004
NEXT_PUBLIC_AUTH_MICROSOFT_ENABLED=
NEXT_PUBLIC_ANALYTICS_ENABLED=
NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN=
NEXT_PUBLIC_POSTHOG_HOST=
NEXT_PUBLIC_SENTRY_DSN=
SENTRY_AUTH_TOKEN=
SENTRY_ORG=
SENTRY_PROJECT=Notes:
NEXT_PUBLIC_CONVEX_URLis the Convex client URL.NEXT_PUBLIC_DOCS_URLis optional: when set, it owns the product app's sidebar and user-menu documentation links (http://localhost:3004locally, your docs domain in production). Leave it unset to hide those links entirely. It can point anywhere — the bundled docs app, a hosted docs site, or a GitHub README — so shippingapps/docsis not required.NEXT_PUBLIC_CONVEX_SITE_URLis the Convex HTTP actions URL used by auth.NEXT_PUBLIC_APP_URLis the product app's canonical metadata URL as well as its auth client/callback URL. Usehttp://localhost:3000locally and your app URL in production.- Static branding is configured in
packages/config/src/brand.ts, not through an app runtime environment variable. Keep backendAPP_NAMEaligned with the brand name for auth and email consistency. - Only set
NEXT_PUBLIC_AUTH_MICROSOFT_ENABLED=trueafter backend Microsoft credentials are configured.
Marketing Site
File: apps/marketing/.env
The marketing site does not use Convex. Every value is public and has a local
default, so the site builds and runs out of the box; set production values before
launch. Its contract lives in packages/env/src/marketing.ts and is re-exported
from apps/marketing/src/env.schema.ts: src/env.ts feeds that schema to
t3-env at build time, and bun check-env runs the same schema, so runtime and
the doctor validate it identically.
NEXT_PUBLIC_SITE_URL=http://localhost:3002
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_DOCS_URL=http://localhost:3004
NEXT_PUBLIC_PURCHASE_URL=
NEXT_PUBLIC_ANALYTICS_ENABLED=
NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN=
NEXT_PUBLIC_POSTHOG_HOST=Notes:
NEXT_PUBLIC_SITE_URLis the canonical marketing URL (metadata base, canonical links, sitemap, robots). Use your marketing domain in production.NEXT_PUBLIC_APP_URLis the "View demo" / app destination behind every CTA.NEXT_PUBLIC_DOCS_URLis the documentation site link.NEXT_PUBLIC_PURCHASE_URLis the optional checkout URL. Until it is set, purchase CTAs render a "coming soon" state instead of dead links.- Analytics is optional and disabled by default.
Documentation Site
File: apps/docs/.env
Every value is public and has a local default, so the docs site builds and runs
out of the box. Its contract lives in packages/env/src/docs.ts and is
re-exported from apps/docs/src/env.schema.ts: src/env.ts feeds it to t3-env
at build time, and bun check-env runs the same schema.
NEXT_PUBLIC_DOCS_URL=http://localhost:3004
NEXT_PUBLIC_SITE_URL=http://localhost:3002Notes:
apps/docsrenders the repository rootdocs/directory with Fumadocs and has no Convex dependency, so it needs no Convex variables.NEXT_PUBLIC_DOCS_URLis the docs site's own canonical URL — it setsmetadataBaseand every canonical/OpenGraph URL. Usehttp://localhost:3004locally and your docs domain (for examplehttps://docs.leavelocalhost.com) in production. A fresh build no longer falls back to adocs.example.complaceholder.NEXT_PUBLIC_SITE_URLis the external marketing site, rendered as the "Marketing site" navbar link. It is not the docs' own canonical URL.- Static branding (app name, logo, GitHub URL) still comes from
@leavelocalhost/configas build-time defaults, so it is not part of this validated schema.
Backend
File: packages/backend/.env
Required for the core app:
APP_NAME=Acme App
CONVEX_SITE_URL=
SITE_URL=
BETTER_AUTH_SECRET=
AUTH_GOOGLE_ID=
AUTH_GOOGLE_SECRET=
RESEND_API_KEY=
RESEND_AUTH_FROM_EMAIL=Common optional values:
AUTH_TRUSTED_ORIGINS=
RESEND_FROM_EMAIL=
RESEND_WEBHOOK_SECRET=
AUTH_MICROSOFT_ID=
AUTH_MICROSOFT_SECRET=
AUTH_MICROSOFT_TENANT_ID=
ANALYTICS_ENABLED=
POSTHOG_COMPONENT_ENABLED=
POSTHOG_PROJECT_TOKEN=
POSTHOG_HOST=Analytics (PostHog) is optional and disabled by default. Set
ANALYTICS_ENABLED=true, POSTHOG_COMPONENT_ENABLED=true, and
POSTHOG_PROJECT_TOKEN to enable backend events. The component flag and token
must also be available to the process that runs convex dev or convex deploy.
See Analytics (PostHog).
Platform super admin (optional — see Super Admin Access):
SUPER_ADMIN_EMAILS=
SUPER_ADMIN_REQUIRE_2FA=SUPER_ADMIN_EMAILS— comma-separated allow-list of emails that may open the/adminpanel. Leave blank to disable the admin panel entirely (no one is a super admin).SUPER_ADMIN_REQUIRE_2FA—trueorfalse. Defaults totruewhen unset: an allow-listed user must also have Better Auth two-factor enabled. Set tofalseonly for local development.
Billing selector:
BILLING_PROVIDER=Supported values:
polarstripelemon_squeezy
Leave BILLING_PROVIDER unset until you want billing validation and billing
provider setup to become active.
Billing Provider Variables
Polar:
POLAR_ORGANIZATION_TOKEN=
POLAR_SERVER=sandbox
POLAR_WEBHOOK_SECRET=
POLAR_PRO_MONTHLY_PRODUCT_ID=
POLAR_PRO_YEARLY_PRODUCT_ID=
POLAR_PRO_LIFETIME_PRODUCT_ID=Stripe:
STRIPE_SECRET_KEY=
STRIPE_WEBHOOK_SECRET=
STRIPE_PRO_MONTHLY_PRICE_ID=
STRIPE_PRO_YEARLY_PRICE_ID=
STRIPE_PRO_LIFETIME_PRICE_ID=Lemon Squeezy:
LEMON_SQUEEZY_API_KEY=
LEMON_SQUEEZY_STORE_ID=
LEMON_SQUEEZY_WEBHOOK_SECRET=
LEMON_SQUEEZY_TEST_MODE=true
LEMON_SQUEEZY_PRO_MONTHLY_VARIANT_ID=
LEMON_SQUEEZY_PRO_YEARLY_VARIANT_ID=
LEMON_SQUEEZY_PRO_LIFETIME_VARIANT_ID=Local Versus Production Values
Local URLs usually look like:
NEXT_PUBLIC_APP_URL=http://localhost:3000
SITE_URL=http://localhost:3000Convex URLs come from the Convex dashboard:
NEXT_PUBLIC_CONVEX_URL=https://your-project.convex.cloud
NEXT_PUBLIC_CONVEX_SITE_URL=https://your-project.convex.site
CONVEX_SITE_URL=https://your-project.convex.siteProduction URLs should use the real deployed app domain, not localhost.
APP_NAME is required because Better Auth uses it as the application name and
TOTP issuer. It also feeds sensitive-action email subjects and sender fallback
names. Do not leave it blank in production.
Validation
Run:
bun check-envUse release mode before launch:
bun check-env --releaseSee Setup Doctor for the full command reference.