Environment variables
Every variable in the Next.js + Convex starter, split between the web env file, the admin env file and the Convex deployment.
This kit keeps configuration in three places. The web app reads apps/web/.env.local, the admin app reads apps/admin/.env.local, and everything that Convex functions need lives as deployment environment variables, set with pnpm exec convex env set NAME value from the repository root. A frontend env file never configures the backend.
Variables prefixed NEXT_PUBLIC_ are bundled into the browser. Everything else is server-only. Use placeholders below; never commit real values.
Values written by the local bootstrap
pnpm dev runs scripts/bootstrap-convex-local.ts, which writes these into the two app env files and keeps your other entries. In production you set them on each host yourself.
| Variable | File | Required | Purpose | Where the value comes from |
|---|---|---|---|---|
NEXT_PUBLIC_CONVEX_URL | both apps | Yes | Browser and server connection to Convex. The Convex client provider throws without it | Local: CONVEX_URL from the CLI-generated root .env.local. Cloud: the deployment URL (https://<name>.convex.cloud) |
CONVEX_SITE_URL | both apps | Yes for web | HTTP action origin of the deployment, also used as the Convex Auth issuer domain in auth.config.ts | Local: root .env.local. Cloud: https://<name>.convex.site |
CONVEX_DEPLOYMENT | apps/web/.env.local | CLI only | Tells the Convex CLI which deployment apps/database scripts target | Local: local:... or anonymous:.... Cloud: your deployment name |
NEXT_PUBLIC_SITE_URL | both apps | Yes | Public origin of each app | http://localhost:3000 for web, http://localhost:3002 for admin; your domains in production |
APP_ENV | both apps | Yes locally | Marks the local environment; the bootstrap sets local | Set by the bootstrap |
NEXT_PUBLIC_ADMIN_APP_URL | apps/web/.env.local | Yes | Admin origin that the web app links to (impersonation banner, admin consent hand-off) | http://localhost:3002 locally; your admin domain in production |
NEXT_PUBLIC_WEB_APP_URL | apps/admin/.env.local | Yes | Customer web origin the admin app links to, sends impersonation handoffs to and calls /api/revalidate on | http://localhost:3000 locally; your web domain in production |
REVALIDATE_SECRET | both apps | Yes | Shared secret for POST /api/revalidate on the web app. Must be identical in both apps | The bootstrap generates one and writes the same value to both files |
The root .env.local (CONVEX_DEPLOYMENT, CONVEX_URL, CONVEX_SITE_URL) is generated by convex dev, is git-ignored, and is only read by the bootstrap script.
apps/web/.env.local.example
These are the entries in the example file, in order. Copy it only when apps/web/.env.local is missing. The first four are commented out in the example because the bootstrap writes them; fill them in by hand only for a cloud deployment.
| Variable | Required | Purpose | Where the value comes from |
|---|---|---|---|
APP_ENV | Generated | local marks the local environment | Written by the bootstrap; unset in production |
NEXT_PUBLIC_CONVEX_URL | Generated | Convex deployment URL | Written by the bootstrap; https://<name>.convex.cloud in production |
CONVEX_SITE_URL | Generated | Convex HTTP actions origin | Written by the bootstrap; https://<name>.convex.site in production |
CONVEX_DEPLOYMENT | Generated, CLI only | Deployment the Convex CLI targets | Written by the bootstrap; local:... or anonymous:... locally |
NEXT_PUBLIC_SITE_URL | Yes | Website origin (also written by the bootstrap) | http://localhost:3000 |
NEXT_PUBLIC_SUPABASE_URL | Legacy | Placeholder read by remaining Supabase-era code paths under apps/web/src and by next build. Convex does not use it | Keep the placeholder from the example; do not point it at a project |
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY | Legacy | Same as above | Placeholder |
SUPABASE_SECRET_KEY | Legacy | Same as above, server-only | Placeholder |
SUPABASE_DATABASE_PASSWORD | Legacy | Unused by Convex | Placeholder |
SUPABASE_PROJECT_REF | Legacy, commented out | Unused by Convex | Leave commented |
STRIPE_SECRET_KEY | Optional | Stripe API access in apps/web/src/payments/ and /api/stripe/webhooks | Stripe dashboard |
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY | Optional | Stripe.js in the browser | Stripe dashboard |
STRIPE_WEBHOOK_SECRET | Optional | Verifies webhook signatures | stripe listen locally, webhook settings in production |
ADMIN_EMAIL | Yes for app emails | from address for emails the Next.js server sends (invitations, account emails) | An address verified with your email provider |
RESEND_API_KEY | Production | Resend key for emails sent by the Next.js server. Separate from the backend's AUTH_RESEND_KEY | Resend dashboard |
USE_LOCAL_EMAIL | Optional | true posts to a Mailpit server at http://localhost:54324, which this kit does not start | true or unset |
NEXT_PUBLIC_POSTHOG_API_KEY | Optional | PostHog analytics | PostHog project settings |
NEXT_PUBLIC_POSTHOG_APP_ID | Optional | PostHog | PostHog project settings |
NEXT_PUBLIC_POSTHOG_HOST | Optional | PostHog ingestion host | PostHog project settings |
NEXT_PUBLIC_GA_ID | Optional | Google Analytics | Google Analytics property |
UNKEY_ROOT_KEY | Optional | Unkey API key management (src/data/user/unkey.ts) | Unkey dashboard |
UNKEY_API_ID | Optional | Unkey API id | Unkey dashboard |
TWITTER_API_KEY, TWITTER_API_SECRET | Legacy | Supabase-era social provider keys. Convex Auth never reads them | Leave as placeholders |
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET | Legacy | Not read by Convex Auth; use AUTH_GOOGLE_ID and AUTH_GOOGLE_SECRET on the backend instead | Leave as placeholders |
GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET | Legacy | Not read by Convex Auth; use AUTH_GITHUB_ID and AUTH_GITHUB_SECRET on the backend instead | Leave as placeholders |
REVALIDATE_SECRET | Yes | Required in the x-revalidate-secret header for POST /api/revalidate; the admin app sends it after publishing content | The bootstrap generates one and keeps the same value in apps/admin/.env.local |
OTEL_ENABLED | Optional | Turns on OpenTelemetry in instrumentation.ts | true or false |
OTEL_SERVICE_NAME | Optional | Service name for traces | Default nextbase-ultimate-web |
OTEL_EXPORTER_OTLP_ENDPOINT | Optional | OTLP collector endpoint | Your collector, default http://localhost:4318 |
OTEL_EXPORTER_OTLP_HEADERS | Optional | Extra OTLP headers | Your collector |
LOG_LEVEL | Optional | Structured logger verbosity | info by default |
NEXT_PUBLIC_ADMIN_APP_URL | Yes | Origin of the separate admin app (also written by the bootstrap) | http://localhost:3002 |
Two variables are read by the code but are not in the example: NEXT_PUBLIC_SENTRY_DSN (Sentry client, server and edge configs) and OPENAI_API_KEY (the /api/chat route and image generation; it appears in apps/web/.env.test). Add them to apps/web/.env.local if you enable those features.
apps/admin/.env.local.example
The admin app has its own, much shorter example. The bootstrap writes apps/admin/.env.local for you locally.
| Variable | Required | Purpose | Where the value comes from |
|---|---|---|---|
NEXT_PUBLIC_SITE_URL | Yes | The admin app's own origin | http://localhost:3002 locally; your admin domain in production |
NEXT_PUBLIC_WEB_APP_URL | Yes | The customer web origin: links back to the web app, the impersonation destination and the /api/revalidate target | http://localhost:3000 locally; your web domain in production |
NEXT_PUBLIC_CONVEX_URL | Yes | Convex deployment URL, the same value as the web app | https://<name>.convex.cloud |
NEXT_PUBLIC_CONVEX_SITE_URL | Listed | Convex HTTP actions origin. Listed in the example; the admin code does not currently read it, and the bootstrap writes CONVEX_SITE_URL instead | https://<name>.convex.site |
REVALIDATE_SECRET | Yes | Must match the web app's value; safe-action.ts refuses to revalidate without it and NEXT_PUBLIC_WEB_APP_URL | Same value as apps/web/.env.local |
The admin code also reads ADMIN_EMAIL, RESEND_API_KEY, USE_LOCAL_EMAIL, the STRIPE_* keys and the legacy Supabase placeholders from its environment; they are not in its example file. Add them to apps/admin/.env.local if a feature or build needs them.
Convex deployment variables
Set these with the CLI against the deployment you have selected. The local bootstrap sets JWT_PRIVATE_KEY, JWKS, SITE_URL, ADMIN_SITE_URL and APP_ENV for you.
pnpm exec convex env set SITE_URL https://example.com
pnpm exec convex env set ADMIN_SITE_URL https://admin.example.com
pnpm exec convex env set AUTH_RESEND_KEY re_xxx
pnpm exec convex env set AUTH_EMAIL_FROM "Nextbase <auth@example.com>"
pnpm exec convex env set MCP_APP_URL https://example.com| Variable | Required | Purpose | Where the value comes from |
|---|---|---|---|
JWT_PRIVATE_KEY | Yes | Convex Auth signing key (RS256, PKCS8) | Generated by the bootstrap locally. For a cloud deployment, generate your own pair |
JWKS | Yes | Public JWKS matching JWT_PRIVATE_KEY | Same as above |
SITE_URL | Yes | Website origin. Validates auth redirects (lib/auth_redirect.ts), builds password reset links, and is the last fallback for the MCP consent URL | Your website origin |
ADMIN_SITE_URL | Yes with the admin app | Admin origin. Added to the auth redirect allowlist so admin login and magic-link callbacks return to the admin app, and used as the consent page origin for the Admin MCP | Your admin origin |
APP_ENV | Yes locally | local or test makes auth emails log to the console instead of sending | local from the bootstrap; unset in production |
AUTH_RESEND_KEY | Production | Resend key used by convex/auth.ts for verification, magic link and password reset emails | Resend dashboard |
AUTH_EMAIL_FROM | Production | Sender for those emails | A sender on your verified Resend domain |
AUTH_GITHUB_ID, AUTH_GITHUB_SECRET | Optional | Registers the GitHub provider when both exist | GitHub OAuth app |
AUTH_GOOGLE_ID, AUTH_GOOGLE_SECRET | Optional | Registers the Google provider when both exist | Google Cloud OAuth client |
MCP_APP_URL | Production | Canonical website origin used for the User MCP consent redirect and the browser origin allowlist. Falls back to APP_URL, then SITE_URL | Your website origin |
CONVEX_SITE_URL | Supplied | The deployment's .convex.site origin. Convex provides it; the MCP code throws if it is missing | Provided by Convex |
The bootstrap refuses to run against a deployment whose name does not start with local: or anonymous:, so it cannot write these to a shared environment by accident.
For how the auth variables are used, see authentication. For production, see deployment.