$ grep -r "VITE_" dist/ | head -3My environment variables work locally and are empty in production
The values are baked in at build time. Adding them afterwards is too late by design.
Seen in apps built with Lovable, Bolt, Replit.
Lovable projects have a .env.example, so for the other 84 the list of variables the app needs is written down nowhere.
100 public Lovable repositories, read 2026-08-03 · method and scripts in the measurements
What is actually happening
Vite replaces `import.meta.env.VITE_SOMETHING` with the literal value while building. After that the value is a string inside the bundle; the running app never looks it up again.
So the environment of the server that serves the files is irrelevant. What matters is the environment of the machine that ran the build.
Two consequences follow. Setting the variable in a hosting dashboard after the build does nothing until you build again. And every value handed to the browser this way is readable by anyone who opens the file.
Confirm it in one command
grep -r "VITE_" dist/ | head -3
Finding the literal value in the built files is normal and expected — that is where it is supposed to end up. Finding the variable name instead means it was never substituted.
Fixing it yourself
- Set the variables where the build runs, then build again.
- Check the result in the built output rather than in the dashboard — the bundle is the only place that tells the truth.
- Write a `.env.example` listing the names with empty values, so the next person does not have to read the code to find out what is required.
Where it stops being a small job
When a value that should never have reached the browser is already in the bundle. Then the question is not how to configure it, but what that value can be used for by a stranger — and answering that requires looking at the service on the other end.
If something is already in the bundle that should never have been, the useful question is what a stranger could do with it. That one we would rather answer properly than quickly.
Send us the app