You changed an environment variable in your hosting dashboard, saved it, and production still uses the old value. This post is for the person who can reach the hosting settings but does not write the build configuration. By the end you can compare the two timelines, find which build is live, and decide whether a new build is the correct next step.
For the Vite and Next.js client builds covered here, the obvious answer — save the setting again — is incomplete. The build ran before the setting changed, so the build did not include the new value.
All platform documentation linked below was checked on 2026-09-23. The Supabase GitHub issue keeps its original 2023 date because it is historical evidence, not current platform documentation.
TL;DR
- You changed a value in the hosting dashboard, saved it, and production still uses the old value, usually with no error at all.
- In common Vite and Next.js client builds, the build copies public variables into the browser files instead of reading them live. A correctly scoped dashboard value is what the next build receives. It is not evidence of what an older live build contains.
- Compare when the intended value became effective with when the current build ran. An older build makes this the strongest candidate, and Check B below is what confirms it.
What you see
At first, nothing looks broken. In this failure mode, the app continues to use an old API URL, public identifier, or feature setting. It does not always crash or show an error.
If a host moves existing browser files from one environment to another, production gets the behavior of the staging environment. This depends on whether promotion serves those files or runs a new build.
An empty value can instead stop a client from initializing. One reported Supabase example appears in a GitHub issue opened May 7, 2023:
supabaseUrl is required.
That message identifies a missing URL. The build, the dashboard, or the step between them can be where the value was absent, and this is one symptom among several.
If Next.js shows its generic production error page instead, preserve the first Console error before changing the environment again. The application error and client-side exception after deploy diagnosis separates a missing build value from version skew and a failed request.
Why the dashboard change did not update production
Re-saving or retyping the dashboard value checks that the setting exists. It does not alter files that were built earlier. Vercel’s environment-variable documentation says changes apply to new deployments, not previous ones.
A refresh cannot create a build that was never run. Clearing the browser cache fetches another copy of whatever the production domain serves; if production still points at the old deployment, the files are still old.
If a server or container restart does not run a new build, the new process serves the same browser files. For a Next.js browser variable with the NEXT_PUBLIC_ prefix and a direct process.env.NEXT_PUBLIC_* reference, a change to the process environment after next build does not rewrite those files. The Next.js environment-variable guide documents that the build inlines those values.
A local .env file answers a different question: what a future local build would read. Each of these attempts checks the value or the browser, while the open question is which build has which value.
How the build supplies the browser value
For the Vite and Next.js browser variables covered here, the sequence is short:
- A value exists in the build environment.
- The build tool reads it when it makes the browser files.
- The build tool writes the value into those files.
- The host serves those files until another deployment replaces them.
selected environment
↓
build
↓
browser files
↓
production deployment
promotion path:
rebuild → reads destination environment again
reuse → keeps values already in the existing files
That is what “env variables baked into build” means in this pattern: the dashboard can be entirely correct and still describe a value that only a future build will receive. A host-specific configuration file or environment scope may override which value that build reads.
Vite replaces public values during the build
Vite exposes browser variables through import.meta.env. By default, Vite exposes only variables with the VITE_ prefix to the browser files, and replaces their references when it builds the app. The Vite environment and mode guide documents this behavior.
If the build ran while the value was absent, a Vite env variable stays undefined in production, even after you correct the dashboard. Vite also warns that it puts VITE_* values into the browser files, so they must not contain secrets.
Next.js inlines direct NEXT_PUBLIC_ references
Next.js uses a similar mechanism for browser variables with the NEXT_PUBLIC_ prefix. During next build, the build replaces direct references such as process.env.NEXT_PUBLIC_ANALYTICS_ID with the value from that build environment. After that, the browser files no longer follow changes to those variables, according to the Next.js environment-variable documentation.
This mechanism does not inline dynamic lookups such as process.env[name]. The build-time explanation in this post applies to the documented direct references.
This also explains why one Docker image used in several environments keeps the NEXT_PUBLIC_ values from the environment that built it. A restart in production does not give its browser files new values.
Promotion and rollback depend on whether a rebuild happens
If promotion moves the same browser files, it also moves the values inside them. If promotion performs a new build, the new build can read the destination environment’s values instead. “Promote” is therefore not enough information; you need to know whether your host rebuilds or reuses.
Vercel documents both paths. Promoting a preview deployment to production performs a complete rebuild with production variables. A staged-production promotion does not trigger a rebuild, and Instant Rollback reassigns an earlier deployment without rebuilding its environment variables. The distinction is in Vercel’s promotion and rollback documentation.
Netlify documents that environment-variable changes require a build and deploy to take effect. A custom script or framework-specific variables can copy values into site code during the build. Variables in netlify.toml override same-name values set through the UI, CLI, or API, so a fresh build can still receive a different value than the dashboard entry suggests.
What applies to your host: the button label is not the point. The question is whether that action makes new browser files from the intended environment, or serves files that already exist. Vercel documents different behavior for preview promotion, staged-production promotion, and Instant Rollback; Netlify documents that environment-variable changes require a build and deploy to take effect.
How to check which value the live build has
Use these checks only on a live app that you own or are authorized to operate. They answer one question: does your own live feature use the public value you expect? Do not use a secret as the search value. Users can see browser variables and request destinations.
The two checks keep the evidence, and they do not assume that every host uses the same labels. Vercel lists deployments with timestamps and Git metadata, and shows build details. Where the plan includes them, Vercel Activity and Audit Logs record changes to environment variables (rollback guide, Audit Logs). Netlify documents that a change to an environment variable needs a build and a deploy before it takes effect.
| Check | What you do | Pass | Fail |
|---|---|---|---|
| A. Compare the timeline | Write down when the intended value became effective. Use the dashboard, the audit log or your own change record. Then open the deployment that serves the production domain and write down when its build started. | The build started after the value became effective. The times permit the new value. Continue with Check B. | The build started before the value became effective. That supports this cause. |
| B. Check the live feature | Open the live feature that uses the value. In DevTools, use the feature and check the Network destination or the public configuration on the page. | The feature uses the destination or public value that you expect. | The feature uses the old destination, or the value you expect is missing. |
Check A needs a change time you can trust. On Vercel, deployment records show timestamps and Git and build metadata. Changes to environment variables appear in Activity or Audit Logs on the accounts and plans that include them (rollback guide, logs overview). If your host has no change time you can trust, mark Check A inconclusive. Do not estimate one. Dashboard labels are different on each host, so use the deployment that serves the production domain, not a status word.
A newer build time is not sufficient evidence, because a build can run against the wrong environment, or without the variable. Check B tests the result instead. With the live feature open, you can also search the browser files for a part of the value that is distinctive and not secret, such as its API hostname. Use that only as supporting evidence. A match in a file that the feature does not use shows nothing, and a search that finds both values, or neither, is inconclusive.
How to fix it safely
Do not start with the deletion of the current deployment. Keep a deployment that you can go back to. A recorded deployment is a usable rollback point only if your host can restore it, and if later changes to code, databases or external services did not make it incompatible.
- Record the current live deployment identifier and its build time. This is your candidate rollback point.
- Check that the intended production environment contains the value you expect. Check that no configuration source with a higher priority replaces it. Do not copy secret values into notes or screenshots. How this desk handles access and evidence sets the same limit for anything you send to us.
- Trigger a new build for that environment. Do not choose an action that only reassigns the production domain to an existing build.
- Wait for the new deployment to complete. Then check that it is the deployment that serves the production domain.
- Do Check B again on the live feature. A successful build is not sufficient. The live feature must use the public value that you expect.
- If the application is incorrect, and the recorded deployment is still compatible with the current data and services, use the rollback path of your host. If it is not compatible, stop and investigate before you make another production change.
Each host has its own controls. The Vercel production recovery guide keeps five steps apart: find the live deployment, read its build metadata and logs, test a new deployment, promote it, and check production. Vercel documents that a rollback sends production traffic to an earlier deployment and does not run a new build. Instant Rollback also warns that external APIs, databases and other dependencies can have changed since that deployment (production rollback guide, Instant Rollback). Netlify documents that a rollback of a deploy does not restore a connected database to its earlier state, so an old front end is not a complete system rollback (backup and recovery).
One action affects the whole front end here, not one setting. A new build includes every code change and dependency change that is in that build input.
A rollback to an earlier deployment also restores the code and the values inside that deployment. This procedure tests one thing: whether the active feature received the intended public value. Whether that value points at the right service or data is a separate question.
How to stop this recurring
Treat every change to a browser variable as a deployment:
- Change the value in the intended environment and check for configuration overrides.
- Build for that environment.
- Confirm which deployment serves the production domain.
- Check the public value that you expect in the live feature.
Before the next incident, write down whether each redeploy, promote and rollback path runs a new build or serves existing browser files. A build identifier or build time on an admin screen makes “which build is live?” a quick check instead of an investigation.
A value that must change without a new build needs a different path: the app must read it at runtime, usually from the server or an API. That path is separate development work and is outside this repair.
When this is bigger than it looks
The harder cases are operational. In some systems, several apps use one built image. A rollback can restore an older key or URL, and the team may not know whether promotion runs a new build or serves existing files. One value can then affect several deployments. A self-repair that nobody checks can make the incident larger.
How App Rescue Desk scopes this incident
For this kind of incident, we first find which deployment serves the production domain, when it was built, and which environment gave it its browser values. We do that before we change production. We then separate three causes that look alike: the build never received the value, the correct build exists but is not live, or the symptom comes from another layer such as the data service.
This maps to incident diagnosis for web apps. The output is the affected component and a defined repair scope, written down before any production change. Several apps sharing one image, an old value returning after rollback, and an undocumented promotion path are included in diagnosis. Open-ended pipeline redesign is not.
The dashboard and the live build answer different questions
The dashboard shows a value that a future build in the selected environment can receive. The browser files show what a completed build contained. If the live feature uses the value you expect, this deployment received it, and that is sufficient to stop the cycle of re-saving the setting. Three questions stay open: whether the value itself is correct, whether every open tab has loaded the new build, and whether a wrong endpoint, a service failure, a configuration override or another deployment layer is also present. A value that the server reads at runtime, or that the app reads from a configuration API, follows different rules. Next.js documents runtime server reads separately from build-time NEXT_PUBLIC_ inlining in its environment-variable guide.
For a Lovable app, a different comparison applies when the preview reaches the expected endpoint but the custom domain shows Failed to fetch. The Lovable preview and custom-domain request check separates a wrong production endpoint from a rejected Origin or OPTIONS request.
If this is happening now
If a value you changed still is not what your users get, or a release carried the wrong environment’s settings into production, send the bug fix request. The desk first identifies which build is live and what it was built with, with scope and price agreed before anything in production changes.