GUIDE · SECURITY
API key in frontend code: how to find and remove it
Why NEXT_PUBLIC_ and VITE_ variables are public, and how to replace a leaked key.
3 min readLast checked
Why frontend variables are public
Next.js inlines variables with the prefix NEXT_PUBLIC_ into the JavaScript that is sent to the browser at build time. Variables without this prefix stay on the server.
Vite says it explicitly: variables with the prefix VITE_ are visible in the client source code, and VITE_ variables should not contain sensitive information such as API keys.
How to search the bundle
Open the page in the browser, then the developer tools, tab “Sources” or “Network”, and search for typical key patterns, for example sk- or sk_live_. Or run the check.
What “remove” really means
A key that was public once counts as known. Deleting it from the code is not enough.
Revoke the key with the provider and create a new one. Move the call into a server route and store the new key only there, as a secret.
Secret or publishable
Stripe has publishable keys (pk_…) and secret or restricted keys (sk_… and rk_…). According to Stripe, only publishable keys can safely be exposed outside the backend. The others belong in the hosting platform’s secrets store or in the backend’s environment variables.
Common mistakes
These mistakes follow from the Next.js, Vite and Stripe documentation:
- Naming a secret key with
NEXT_PUBLIC_orVITE_so that it “reaches” the browser. That is exactly what puts it into the shipped code. - Changing a
NEXT_PUBLIC_variable only in the hosting settings. According to Next.js the app no longer responds to changes after the build; the value is frozen at build time. Rebuild the app afterwards. - Committing local env files. Next.js says you almost never want to commit
.envfiles; Vite recommends adding*.localto your.gitignore. - Putting secret keys into source code or configuration files that go into version control, or sharing them by e-mail or chat. Stripe advises against both.
- Only deleting an exposed key from the code instead of revoking or rotating it.
Example: keep the key on the server
The secret key lives in a variable without a public prefix and is read only in a server route. For server-side code, Stripe’s documentation recommends restricted keys (rk_…). The file belongs in .gitignore; on your hosting you store the same variable as a secret:
# .env.local (do not commit)
STRIPE_API_KEY=rk_live_…
// app/api/checkout/route.js: runs on the server only
export async function POST() {
const key = process.env.STRIPE_API_KEY
// … call Stripe with key
}Frequently asked questions
Is every variable with NEXT_PUBLIC_ a problem?
No. It is meant for values that may be visible in the browser, such as an analytics ID or, with Stripe, the publishable key (pk_…). It is only a problem if the value has to stay secret.
Is it enough to delete the key from the code?
No. Once a key has been exposed, treat it as known. Stripe says you must revoke a compromised key. Fix the cause, create a new key and replace it everywhere.
How do I replace a Stripe key without downtime?
Rotate it in the dashboard and pick a point in the future under “Valid until”, not “Now”: with “Now” the old key is deleted immediately. According to Stripe, the old and the new key then both work for up to 7 days. Move a subset of your servers first and let the old key expire only once its requests are down to zero.
Can I change a NEXT_PUBLIC_ variable after the build?
Not without a new build. The value is inserted into the code at build time. For values that are only known at runtime, Next.js says you need your own API that delivers them to the browser.
Sources
Check your app
The free check loads your app like a visitor and shows what is visible from the outside. You confirm beforehand that you are responsible for the app or authorised to test it.