NEXT_PUBLIC_ prefix on a secret
What it looks like
# .env.local
NEXT_PUBLIC_SUPABASE_URL=https://abcd1234.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ... # fine: public by design
NEXT_PUBLIC_STRIPE_SECRET_KEY=sk_live_... # inlined into the browser bundle
NEXT_PUBLIC_OPENAI_API_KEY=sk-proj-...What happens
The build writes the secret's value into public JavaScript, so anyone who loads the site can read it, and a redeploy with the same variable name republishes it.
Where it shows up
Descriptive, not a verdict: builders and stacks whose defaults make this reachable, or that a public incident names. Each hub states the tool's own security features.
Seen in public
Escape analysed more than 5,600 publicly deployed apps built with AI app builders and found more than 2,000 vulnerabilities, over 400 exposed secrets and 175 instances of exposed personal data.
- more than 5,600 Apps analysed
- more than 2,000 Vulnerabilities found
- 400+ Exposed secrets
- 175 Exposed PII instances
Oct 2025 · Escape · all sources
Check it yourself
Uses your builder's dashboard and your browser. No tools to install.
- In your hosting dashboard (Vercel: Project, Settings, Environment Variables) or your
.envfiles, list every variable whose name starts withNEXT_PUBLIC_. - For each one, ask whether the provider calls that value secret, private, server or admin. Stripe secret keys, model provider keys, database passwords and Supabase service_role keys all fall in that group.
- Open the live site in Chrome, right-click, choose Inspect, open the Sources tab and press Ctrl+Shift+F. Search for the first few characters of each suspect value.
- A bad result is a
NEXT_PUBLIC_variable holding a server-only key, or a search hit for that key's value in a loaded script.
What we check
We list every value inlined into the production bundle, match each to a provider and test whether it is live and what it can do. The report names the variable, where it appears in the built files and the scope it grants.
Fix direction
Remove the NEXT_PUBLIC_ prefix from the secret so it stays on the server, and read it only inside a Route Handler, Server Action or server component. Rotate the value, then redeploy so the new build no longer contains the old key.
Mechanism documented in: How to use environment variables in Next.js (verified 2026-09-21).
Covered by
Pre-launch check ($490, 48 hours) and Security sweep ($290, 24 hours)
Both include a re-check after your fixes.
Related patterns
- Service-role key shipped in the browser bundleSecrets and keysCritical
Anyone who opens the app can copy the key from the downloaded JavaScript and read, change or delete every row in every table.
- Third-party API key in the JavaScript bundleSecrets and keysHigh
Anyone who views the page source can take the key and run up charges, send messages or pull data on your account until the key is revoked.
- Secrets committed to the code repositorySecrets and keysCritical
Everyone who can see the repository, now or later, holds working keys to the database, payment account and model provider, and the keys stay in history after the file is deleted.
- LLM API key exposed to the clientAI featuresCritical
Anyone who views the page source can copy the key and run their own workloads on your account until the bill or the provider stops them.
Questions
are next_public environment variables secure
They are public by design. Next.js documents that a variable prefixed with NEXT_PUBLIC_ is inlined at build time into the JavaScript delivered to the browser, replacing each reference with the literal value. Use the prefix only for values meant to be public, such as a site URL or an anon key. Variables without the prefix stay on the server.
how do i keep an api key secret in next js
Store it as an environment variable without the NEXT_PUBLIC_ prefix and read it only in server code: a Route Handler, a Server Action or a server component. The browser calls your route, and your route calls the provider with the key. Next.js keeps non-prefixed variables out of the client bundle.
why is my env variable undefined in the browser next js
Because Next.js only exposes variables that start with NEXT_PUBLIC_ to browser code; everything else is server-only. Before adding the prefix, check whether the value is a secret. If it is, move the code that uses it to the server instead of exposing the variable.
Back to the catalogue, or run the self-check for your stack.