Skip to Content
Technical ReferenceEnvironment Variables

Environment Variables

The rule that matters

Anything prefixed NEXT_PUBLIC_ is inlined into the browser bundle and readable by anyone who visits the site. No secret may ever carry that prefix.

This has been got wrong before in this codebase: a Gemini API key was exposed this way and had to be rotated.

Client variables

Set in Vercel, or in .env.local for development.

VariablePurpose
NEXT_PUBLIC_CONVEX_URLConvex deployment URL. Also derives the allowed remote image host. The app fails at startup with a clear message if it is missing.
NEXT_PUBLIC_VAPID_PUBLIC_KEYWeb Push public key. Public by design — the private half lives server-side.

Server variables

Set with npx convex env set <NAME> <value>, never in a file.

VariablePurpose
FRONTEND_SITE_URLBase URL for links in emails and shared reports
GEMINI_API_KEYGoogle Gemini, used by convex/functions/ai.ts
VAPID_PUBLIC_KEYWeb Push, public half
VAPID_PRIVATE_KEYWeb Push, private half
VAPID_EMAILContact address required by the Web Push spec
SMTP_HOSTMail server
SMTP_PORT465 for implicit TLS, 587 for STARTTLS
SMTP_USERMail account
SMTP_PASSWORDMail password or app password
SMTP_FROMEnvelope sender address

Generating VAPID keys

node -e "console.log(require('web-push').generateVAPIDKeys())"

Set the public key in both places — as VAPID_PUBLIC_KEY in Convex and as NEXT_PUBLIC_VAPID_PUBLIC_KEY in Vercel. They must match, or push subscriptions are rejected.

Checking what is set

npx convex env list

.env.example in the repository root is the authoritative list. Keep it current when adding a variable.

Last updated on