Environment variables and secrets, explained
Last updated: July 26, 2026
An environment variable is a named setting stored outside your code, often used to hold secrets like API keys. In Next.js and Vite, a prefix such as NEXT_PUBLIC_ or VITE_ publishes that value to the browser. The prefix is a publication marker, not protection, so a prefixed secret is exposed.
What is an environment variable?
An environment variable is a named value your app reads at run time, kept separate from your code. Instead of typing a secret directly into a file, you store it as something like STRIPE_SECRET_KEY and your code refers to the name. This keeps secrets out of your source code and lets you use different values in testing versus production.
Environment variables commonly hold API keys, database connection strings, and other configuration. Getting them right is central to whether your app is secure.
Why does a NEXT_PUBLIC_ or VITE_ prefix expose a secret?
A NEXT_PUBLIC_ or VITE_ prefix exposes a value because that prefix tells the build tool to bake the value into the JavaScript sent to the browser. The prefix is a publication marker, not a lock. Anything carrying it is downloaded by every visitor and can be read in their browser tools.
| Variable name | Where it ends up | Safe for a secret? |
|---|---|---|
STRIPE_SECRET_KEY | Server only | Yes |
NEXT_PUBLIC_STRIPE_KEY | In the browser bundle | No |
VITE_OPENAI_KEY | In the browser bundle | No |
So the rule is simple: a prefixed variable is for values that are fine to make public (a public analytics id, a publishable key). Anything secret must have no such prefix, so it stays on the server.
How secrets leak in AI-built apps
Secrets in AI-built apps most often leak through one honest mistake: a secret gets a browser-exposed name to fix an error. The app's front-end code tries to use a key, the value comes back as "undefined," and the quickest way to make the error disappear is to rename the key with NEXT_PUBLIC_ or VITE_. That silences the error and ships the secret to every visitor.
Other common leaks: sharing one config file between server and browser code, or writing a fallback like process.env.KEY || "real-key-here" that hard-codes the real secret. An AI assistant, told only "make it work," will happily do any of these.
Explain My Build reads your code and flags secret-looking values that carry a browser-exposed prefix, then puts "move server-side and rotate" on your fix-list. If a secret was ever public, rotate the key, don't just rename it. This is a code read, so it flags likely exposure rather than proving abuse.
Frequently asked questions
Is it safe to put an API key in an environment variable?
Yes, as long as the variable has no browser-exposed prefix. A secret stored as a server-only variable like STRIPE_SECRET_KEY stays on your server. The same secret named NEXT_PUBLIC_STRIPE_KEY or VITE_STRIPE_KEY gets published to the browser. See API key.
What does the NEXT_PUBLIC_ prefix actually do?
It tells Next.js to include that variable's value in the JavaScript sent to the browser, so your front-end code can read it. It is meant for values that are safe to be public. It does not encrypt or hide anything, so never put a secret behind it. Vite's VITE_ prefix and CRA's REACT_APP_ work the same way.
I renamed my secret to remove the prefix. Am I safe now?
Not yet. If the secret was ever built with a public prefix, it was already shipped to visitors. Renaming it stops future exposure but does not undo past exposure. You must rotate the key: create a new one, switch over, and revoke the old value.
Turn your app into a guide your users can follow.
Paste a public GitHub link and get your founder runbook + fix-list free in about a minute — no sign-up. Private code runs entirely in your browser.