Home / Fixes / Vercel env

If it starts with VITE_ or NEXT_PUBLIC_, the browser has it.

That prefix is not a naming style. It is an instruction to bake the value into JavaScript the user can download.

Symptoms

Why the builders get the prefix wrong

Vite will not expose process.env.FOO to the client unless it starts with VITE_. The generator needs the Supabase URL in the browser, so it prefixes everything “to be safe.” That includes the service role, the Stripe secret, and the OpenAI key. Bolt and Lovable apps copy that file forward. v0 does the same with NEXT_PUBLIC_.

The actual split

Public (prefix allowed): Supabase URL, Supabase anon key, Stripe publishable key (pk_), public Sentry DSN, public site URL.

Secret (no prefix, server / Vercel only): SUPABASE_SERVICE_ROLE_KEY, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, OPENAI_API_KEY, RESEND_API_KEY, DATABASE_URL, any AWS_SECRET name.

How to set them

  1. Vercel, Settings, Environment Variables. Create each secret without a VITE_ or NEXT_PUBLIC_ prefix.
  2. Tick Production / Preview / Development on purpose. Preview should use Stripe test keys. Production should not.
  3. After changing a public var, Redeploy. They are inlined at build time.
  4. Keep .env and .env.local out of git. Pull with the Vercel CLI if you want a local file.
# names that should never exist
VITE_SUPABASE_SERVICE_ROLE
VITE_STRIPE_SECRET_KEY
NEXT_PUBLIC_SERVICE_ROLE
NEXT_PUBLIC_STRIPE_SECRET
Finding one of those names in the repo is a P0. Rotate the key, then rename. The scanner looks for this; it is the first item on the $39 kit checklist.

A table of names lives in kit/vercel-env.md. Pair this with the service_role and white screen pages — they are the same mistake from two other angles.

$49 to run this against your tree

Zip or GitHub URL in. Ranked HTML/PDF in 24h. No call. First 10 audits are $49, credited if you continue to triage. Email contact@shipready.local.

Start an audit See a sample report