Environment variables in Bolt.new: what goes where
Which values in a Bolt.new app can live in the browser, which must stay in Secrets, how VITE_ and other prefixes work, and how to check that nothing leaked.
Leer en español →
A Bolt.new app has two kinds of settings. Public configuration that the browser needs, like your Supabase URL, the Supabase publishable or anon key and a Stripe publishable key, goes in the project's .env file with the framework's public prefix (VITE_ in most Bolt projects). Secrets, like a Stripe secret key, an OpenAI key or a Supabase secret key, go in Bolt's Secrets settings and are read only by server functions. Anything with a public prefix ends up in the JavaScript that every visitor downloads.
This guide lists common values and where each belongs, explains how the prefixes work, shows where to set them in Bolt and on other hosts, and how to check your live app for leaked keys.
Where does each value belong?
| Value | Safe in the browser? | Where it goes |
|---|---|---|
| Supabase project URL | Yes | .env as VITE_SUPABASE_URL (or similar) |
Supabase publishable key (sb_publishable_...) or legacy anon key | Yes, with RLS on every table | .env |
Supabase secret key (sb_secret_...) or legacy service_role key | No, it bypasses RLS | Secrets, used only in server functions |
Stripe publishable key (pk_test_..., pk_live_...) | Yes | .env |
Stripe secret key (sk_...) and webhook signing secret (whsec_...) | No | Secrets |
| OpenAI, Anthropic, Resend and other API keys | No | Secrets |
| Google Maps browser key | Yes, if restricted to your domains | .env |
| Feature flags, app name, public URLs | Yes | .env |
The rule behind the table: if knowing the value lets someone spend your money, read other people's data or act as your app, it's a secret.
How do the VITE_, NEXT_PUBLIC_ and EXPO_PUBLIC_ prefixes work?
The prefix is how the framework decides what to copy into the browser bundle. Vite's documentation says only variables starting with VITE_ are exposed to your client code, through import.meta.env. Next.js does the same with NEXT_PUBLIC_, and Expo with EXPO_PUBLIC_.
That makes the prefix a label that says "public". The mistake to watch for is the opposite of what people expect: a secret renamed to VITE_OPENAI_API_KEY so that the front end can "see" it. It works, and now the key is in a file anyone can open in their browser's developer tools. Calls that need a secret have to go through a server function instead.
Where do I set them in Bolt?
Public values
Open Code view and look for a .env file at the project root. Edit it there, or ask Bolt to create one. If you don't know which variables the app expects, Bolt's troubleshooting suggests asking: List every environment variable the application requires and where each value can be found.
Secrets
Click the database icon at the top of the project, then Secrets. Enter a Name that matches what the function reads (for example OPENAI_API_KEY) and the Value, then save. According to Bolt's secrets documentation:
- Bolt usually asks you to add a secret after writing code that needs one, and shows a
Missing secretsmessage listing any the code uses but that don't exist yet. - A new secret is available to server functions right away, without redeploying.
- Only the project owner, co-owners and team admins can view or manage secrets.
- If your database is a Supabase project you connected or claimed, the same secrets appear in the Supabase dashboard under Edge Functions > Secrets.
Inside a server function, which runs on Supabase's Deno-based Edge Functions, a secret is read like this:
const apiKey = Deno.env.get('OPENAI_API_KEY');
if (!apiKey) {
return new Response('Server is missing OPENAI_API_KEY', { status: 500 });
}
On another host
If Netlify, Vercel or another host builds your app from GitHub, it doesn't see your Bolt .env file. Add the public variables in that host's settings and rebuild, because VITE_ values are fixed at build time. Secrets used by server functions stay in Bolt or Supabase; the host never needs them. Our guide on Bolt.new deploys failing on Netlify covers what happens when they're missing.
How do I keep test and live values apart?
Use different values for testing and production, not just different apps. With Stripe, the test keys start with pk_test_ and sk_test_, the live ones with pk_live_ and sk_live_, and each mode has its own webhook signing secret. A common launch-day failure is switching the publishable key to live while the server function still has the test secret key. Our guide on production and preview environment variables shows a simple way to organize both.
How do I check that no secret leaked?
Search the built files. Run
npm run buildin the Bolt terminal, then search the output folder for telltale prefixes:grep -rE "sk_live|sk_test|sb_secret|service_role|whsec_" dist/No output is what you want.
- Search the live site. Open your app, then the browser's developer tools. In the Sources panel, search all files for the same prefixes and for the names of your API providers.
- Check GitHub. Make sure
.envis listed in.gitignoreand that no earlier commit contains real keys. A key that was ever committed should be treated as public. - Run Bolt's security audit. On paid plans, Run security audit in the Publish menu checks that private keys aren't stored in code or sent to browsers, and doesn't use tokens.
If you find a secret where it shouldn't be, moving it isn't enough. Rotate it in the provider's dashboard (create a new key, update Secrets, delete the old key), because anyone may already have a copy. Our post on an API key exposed in the front end walks through that cleanup.
Quick answers
Is the Supabase anon key a secret? No. It's designed to be public, and Row Level Security is what protects the data. The service_role or secret key is the one that must never reach the browser.
Why is my variable undefined in the app? Either it lacks the VITE_ prefix, it was added after the last build, or the dev server wasn't restarted after editing .env.
Can I put secrets in .env if the repo is private? Not for anything the front end reads. A private repository protects the source, but the built JavaScript is still public on your site.
Do I need to redeploy after changing a secret in Bolt? Not for server functions, according to Bolt's documentation. Changes to VITE_ values do need a new build.
Not sure what your app is exposing?
The free health check looks at your live app from the outside, which is exactly where leaked keys show up. For a full review of keys, policies and server functions, see our Supabase security review and Bolt app rescue, or ask us a question.


