Skip to content
Documentation

Environment variables

Run npm run setup to create .env.local from .env.example and fill the required values. On Vercel, set the same names under Project > Settings > Environment Variables, or use the Deploy with Vercel button in the README. Never commit real values.

Anything that starts with VITE_ ends up in the browser bundle, so only public values use that prefix. Keys that grant extra access stay server-only.

Reference

VariableBrowser?PurposeWhere to find it
VITE_SUPABASE_URLYesSupabase API URLProject Settings > API > Project URL. Local: npx supabase status
VITE_SUPABASE_PUBLISHABLE_KEYYesAnon or publishable keyProject Settings > API, anon or publishable key. Local: npx supabase status
VITE_AUTH_GOOGLE_ENABLEDYesSet to true to show Google on /login and /signupAlso enable Google under Authentication > Providers in Supabase
APP_URLNoYour site's public origin, used in sign-up and password reset emails. No trailing slash.Your production URL, for example https://www.example.com. Local: http://localhost:3000
SUPABASE_SERVICE_ROLE_KEYYesRequired. Admin user tools (create and delete users, change emails and passwords), API token lookup, and production buildsProject Settings > API > service_role
SUPABASE_JWT_SECRETYesRequired. Signs short-lived sessions for API and MCP tokensProject Settings > API > JWT Keys. Local: npx supabase status
MEDIA_UPLOAD_TICKET_SECRETNoSigns admin media upload ticketsRun npm run secrets:generate
CONTACT_IP_HASH_SECRETNoHashes visitor IPs for the contact form rate limit. Required in productionRun npm run secrets:generate
RESEND_API_KEYNoOptional. Emails each contact form message to your contact emailresend.com > API Keys
CONTACT_FROM_EMAILNoOptional. Sender address for contact emails, needed with RESEND_API_KEYAn address on a domain verified in Resend

The server also accepts VITE_SUPABASE_ANON_KEY and VITE_SUPABASE_KEY as older names for the publishable key. Use VITE_SUPABASE_PUBLISHABLE_KEY for new projects.

Example

ENV
VITE_SUPABASE_URL=http://127.0.0.1:54321
VITE_SUPABASE_PUBLISHABLE_KEY=
VITE_AUTH_GOOGLE_ENABLED=false
APP_URL=http://localhost:3000
SUPABASE_SERVICE_ROLE_KEY=
SUPABASE_JWT_SECRET=
MEDIA_UPLOAD_TICKET_SECRET=
CONTACT_IP_HASH_SECRET=

Generating app secrets

Run npm run secrets:generate to create random values for the secrets the app owns: CONTACT_IP_HASH_SECRET and MEDIA_UPLOAD_TICKET_SECRET. It adds only the keys missing from .env.local, keeps existing values, and prints key names only.

For Vercel, run npm run secrets:generate -- --print. It prints KEY=value lines to paste into Project > Settings > Environment Variables and does not write any file. Treat that output as secret and don't paste it anywhere else.

Supabase and Resend keys come from their own dashboards.

Notes on APP_URL

  • In production it must use https. Loopback addresses are the only exception.
  • On Vercel Preview you can leave it unset. Links then use the deployment's own https://<deployment>.vercel.app address.
  • In Supabase, under Authentication > URL Configuration, set Site URL to your APP_URL and add <APP_URL>/auth/callback and <APP_URL>/reset-password as redirect URLs.

Notes on the secret keys

  • Never put the service role key in a VITE_ variable. It bypasses row level security.
  • SUPABASE_SERVICE_ROLE_KEY and SUPABASE_JWT_SECRET are required for npm run build and for production deploys. Without the service role key, the Users screen can't create or delete accounts. Without the JWT secret, the API and MCP screen won't create tokens. Supabase projects that only use asymmetric JWT signing keys aren't supported for tokens.
  • Without CONTACT_IP_HASH_SECRET, the contact form won't save messages in production. Locally a development fallback is used.
  • If a secret leaks, rotate it in Supabase and update Vercel straight away.

Vercel

NameEnvironments
VITE_SUPABASE_URLProduction, Preview
VITE_SUPABASE_PUBLISHABLE_KEYProduction, Preview
APP_URLProduction (your live domain)
SUPABASE_SERVICE_ROLE_KEYProduction, Preview
CONTACT_IP_HASH_SECRETProduction, Preview
SUPABASE_JWT_SECRETProduction, Preview

Redeploy after changing environment variables so the new values are picked up.