Vercel Environment Variables: What Is Actually Safe to Expose and What Is Not - VibeDoctor 
← All Articles 🚀 Deployment & Infrastructure Critical

Vercel Environment Variables: What Is Actually Safe to Expose and What Is Not

NEXT_PUBLIC_ confusion is universal. Learn which Vercel env vars are safe for the browser and which ones expose your secrets to the world.

SEC-006 CFG-005

Quick Answer

Any Vercel environment variable prefixed with NEXT_PUBLIC_ is bundled into your client-side JavaScript and visible to anyone who opens browser DevTools. Database URLs, Stripe secret keys, Supabase service role keys, and API secrets must never have this prefix. If they do, your secrets are already exposed in every browser that loads your site.

The NEXT_PUBLIC_ Problem

Next.js uses a simple naming convention to determine which environment variables are available in the browser: any variable starting with NEXT_PUBLIC_ is inlined into the client-side JavaScript bundle at build time. Variables without this prefix are only available in server-side code (API routes, getServerSideProps, Server Components).

This design is intentional and useful - your app needs some values in the browser (like a Supabase anon key or a Google Analytics ID). The problem is that AI coding tools do not distinguish between browser-safe and server-only secrets. According to GitGuardian's 2024 report, 12.8 million secrets were newly exposed in code repositories in 2023. Client-side bundles are an even more direct exposure vector because they are served to every user.

The Apiiro 2025 AI code research found that secret exposure in AI-generated code occurs at 2.74x the rate of human-written code. Vercel's NEXT_PUBLIC_ prefix is the most common mechanism for this exposure in the Next.js ecosystem.

What Is Safe vs. Dangerous

Variable NEXT_PUBLIC_ Safe? Why
Supabase anon key Yes Designed for browser use, restricted by RLS
Supabase service role key NO Bypasses all RLS, full database admin access
Stripe publishable key (pk_live_) Yes Designed for client-side Stripe.js
Stripe secret key (sk_live_) NO Allows charges, refunds, customer data access
Google Analytics ID Yes Public tracking identifier
OpenAI API key NO Allows unlimited API usage billed to you
DATABASE_URL NO Direct database connection with credentials
App URL / site URL Yes Public information, no secret value
JWT_SECRET NO Allows forging authentication tokens
SendGrid / Resend API key NO Allows sending email as your domain

How AI Tools Create This Problem

// ❌ BAD - AI puts secrets in NEXT_PUBLIC_ variables
// .env.local (what AI generates)
NEXT_PUBLIC_SUPABASE_URL=https://abc.supabase.co
NEXT_PUBLIC_SUPABASE_SERVICE_KEY=eyJhbGci...  // This is the SERVICE key!
NEXT_PUBLIC_STRIPE_SECRET=sk_live_abc123
NEXT_PUBLIC_OPENAI_KEY=sk-abc123
// ✅ GOOD - Only browser-safe values get NEXT_PUBLIC_
// .env.local (corrected)
NEXT_PUBLIC_SUPABASE_URL=https://abc.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGci...  // Anon key is safe

// Server-only (no NEXT_PUBLIC_ prefix)
SUPABASE_SERVICE_KEY=eyJhbGci...
STRIPE_SECRET_KEY=sk_live_abc123
OPENAI_API_KEY=sk-abc123

How to Check for Exposed Secrets on Vercel

  1. Open your deployed site in a browser and go to DevTools > Sources tab.
  2. Search across all sources for strings like sk_live, sk-, service_role, and eyJhbGci.
  3. Check your Vercel dashboard > Settings > Environment Variables. Look for any variable with NEXT_PUBLIC_ prefix that contains a secret value.
  4. Search your codebase for process.env.NEXT_PUBLIC_ and verify each usage is browser-safe.

Vercel-Specific Environment Variable Features

Vercel provides environment scoping that AI tools do not use. Variables can be set per environment (Production, Preview, Development), which prevents preview deployments from using production secrets. Vercel also supports "Sensitive" variables that are encrypted at rest and masked in logs. Always mark secret values as Sensitive in the Vercel dashboard.

What to Do If Your Secrets Are Already Exposed

  1. Rotate immediately. Generate new keys/secrets from each provider's dashboard (Supabase, Stripe, OpenAI, etc.).
  2. Update Vercel env vars. Remove the NEXT_PUBLIC_ prefix, add the new keys, redeploy.
  3. Check access logs. Review your Stripe dashboard, Supabase logs, and OpenAI usage for unauthorized activity.
  4. Set up monitoring. Enable billing alerts on paid API services to catch unauthorized usage early.
  5. Scan your codebase. Tools like VibeDoctor (vibedoctor.io) automatically detect client-side secret exposure (SEC-006) and flag the specific files and variable names. Free to sign up.

FAQ

Why does Supabase have two keys?

The anon key is designed for browser use and respects Row Level Security policies. The service role key bypasses all RLS and has full admin access to your database. The anon key is safe to expose; the service role key must only be used in server-side code. AI tools frequently confuse the two.

Does removing NEXT_PUBLIC_ from a variable fix the exposure?

Removing the prefix prevents future exposure, but if the variable was already deployed with NEXT_PUBLIC_, the secret exists in every cached build artifact and browser cache. You must rotate the secret (generate a new one) and redeploy. The old secret should be considered compromised.

How do I use server-only env vars in Next.js?

Server-only variables (without NEXT_PUBLIC_ prefix) are available in Server Components, API routes (app/api/), getServerSideProps, and middleware. They are not available in Client Components or any code that runs in the browser. Access them with process.env.VARIABLE_NAME in server-side code only.

Does this apply to VITE_ prefix in Vite projects?

Yes, the same concept applies. Vite uses VITE_ prefix instead of NEXT_PUBLIC_, and any VITE_ variable is exposed in the client bundle via import.meta.env. The same rules apply: only browser-safe, non-secret values should use the VITE_ prefix.

What about Vercel Edge Functions - are env vars safe there?

Yes. Vercel Edge Functions run on the server (at the edge), so non-prefixed environment variables are safe there. They never reach the browser. Edge Functions are a good place for API calls that need secret keys.

Scan your codebase for this issue - free

VibeDoctor checks for SEC-006, CFG-005 and 128 other issues across 15 diagnostic areas.

SCAN MY APP →
← Back to all articles View all 129+ checks →