What this usually means
Next.js only exposes environment variables prefixed with NEXT_PUBLIC_ to client-side code. Any variable lacking that prefix will not be bundled or available in browser JavaScript. Also, variables must actually exist at build time: if you change the .env file after a build, your deployed app won't see the updates. Sometimes, variables are missing from deployment environments entirely, or are injected in a way Next.js can’t see (like systemd or shell startup vars). The issue is usually a mismatch between how and when environment variables are loaded and when your code expects them.
The first ten minutes — establish facts before touching code.
- 1Check for NEXT_PUBLIC_ prefix on any variable accessed in client code; grep 'process.env' across your pages/components.
- 2cat .env.local (and .env, .env.production) to see if the variable is defined at all.
- 3In your terminal, run 'printenv | grep MY_VAR' before starting next dev/build to confirm env visibility.
- 4Run 'next build && next start' locally and check whether process.env.VAR is undefined during SSR.
- 5Log process.env in an API route and check deployment logs—does the value appear?
- 6On Vercel/Netlify, confirm the variable is defined in the dashboard's environment section, not just your local files.
The specific files, logs, configs, and dashboards that usually own this bug.
- search.env, .env.local, .env.production files in root of the repo
- searchnext.config.js for custom env injection or rewrites
- searchVercel/Netlify/Render dashboard environment variable settings
- searchDeployment logs for 'undefined' variable access errors
- searchClient bundle (inspect window.__NEXT_DATA__.env in browser console)
- searchAPI route logs (e.g., /api/health) for process.env output
- searchBuild-time terminal output (look for warnings about missing variables)
Practical causes, not theory. These are the things you will actually find.
- warningEnvironment variable missing NEXT_PUBLIC_ prefix for client-side use
- warning.env file changes not reflected because build already ran
- warningForgetting to define variable in hosting provider's dashboard
- warningLoading .env after Next.js build step, so variables aren't injected
- warningnext.config.js misconfigured or not exporting env vars explicitly
- warningTypos in variable names (ENV_NAME vs. ENVNAME)
- warningUsing process.env in getStaticProps/getServerSideProps for client-only vars
Concrete fix directions. Pick the one that matches your root cause.
- buildAdd NEXT_PUBLIC_ prefix to any variable you want on the client side
- buildAlways restart the dev server after editing .env files
- buildRe-run 'next build' after changing environment variables
- buildMirror .env settings in deployment provider’s env settings (never just in files)
- buildExplicitly set missing variables in next.config.js’s env block when needed
- buildCheck for variable spelling and casing consistency everywhere
A fix you cannot prove is a guess. Close the loop.
- verifiedconsole.log(process.env.NEXT_PUBLIC_API_URL) in a client page and confirm value in browser console
- verifiedCheck deployment logs—should show correct variable value at build time
- verifiedVisit an API route that logs process.env and see the expected value
- verifiedInspect window.__NEXT_DATA__.env in browser to see if variable is present
- verifiedDeploy a new build and confirm your changes propagate
- verifiedUse curl to hit the deployed endpoint and check for correct variable-dependent behavior
Things that make this bug worse or harder to find.
- warningModifying .env without restarting the dev/build process
- warningAssuming .env updates propagate automatically in production
- warningUsing server-only process.env variables in client-side code
- warningRelying on OS-level env vars without mirroring in deployment dashboard
- warningLeaving sensitive keys unprefixed—exposes them to the client accidentally
- warningCopy-pasting code that references process.env without checking variable scope
NEXT_PUBLIC_API_URL Undefined After Deploying to Vercel
Timeline
- 09:00Merged feature using process.env.API_URL in client page.
- 09:10next build passes locally; NEXT_PUBLIC_API_URL shows correct value.
- 09:20Deployed to Vercel. Homepage shows blank results; API requests fail.
- 09:22Checked browser console—process.env.NEXT_PUBLIC_API_URL is undefined.
- 09:23Realized .env in repo had API_URL, not NEXT_PUBLIC_API_URL.
- 09:25Added NEXT_PUBLIC_API_URL in Vercel dashboard. Redeployed.
- 09:30Homepage loads fine. Requests go through. Incident resolved.
I pushed a new page that fetches from our backend, using process.env.API_URL in the fetch URL. It worked locally, so I merged and deployed.
On Vercel, the homepage broke. Network tab showed the fetch URL was literally 'undefined'. Logging process.env in the browser revealed NEXT_PUBLIC_API_URL was undefined.
I realized Next.js only exposes NEXT_PUBLIC_ variables to the client. Updating the env var name and redeploying instantly fixed it. I'll never forget the prefix rule again.
Root cause
Environment variable missing NEXT_PUBLIC_ prefix, so it was not exposed to the client bundle.
The fix
Rename variable to NEXT_PUBLIC_API_URL in .env and deployment dashboard, then redeploy.
The lesson
Next.js statically injects env vars at build time—if you miss the NEXT_PUBLIC_ prefix, the variable is invisible in client code, no exceptions.
Next.js statically resolves process.env.* at build time for both server and client code. Only variables prefixed with NEXT_PUBLIC_ are bundled into the client-side JavaScript. All other variables are evaluated on the server at runtime, never sent to the browser.
This means your .env files are read exactly once, during the build or startup process. Any variable added after build time is invisible until you rebuild. This is why hot-reloading sometimes gives false confidence: client code doesn't see new variables unless you restart.
.env and .env.local files are ignored in most CI/CD pipelines. On Vercel, Netlify, and similar, you must set each environment variable in the provider's dashboard. If you don't, those keys will be undefined, regardless of your git state.
Additionally, secret or system environment variables not explicitly surfaced to Next.js (through NEXT_PUBLIC_ or a next.config.js env block) never reach the code where you expect them. Don't trust your local .env to match production unless you check the remote dashboard.
Server-side code (getServerSideProps, API routes) can access any process.env variable, but only if it exists in the node process environment at launch. If you edit .env after 'next start', no update occurs. Always restart your server.
To confirm, log process.env.VARIABLE_NAME in an API route—never in pages/client code. This gives you a live view of what's actually available server-side. Missed this step? You risk chasing client/server confusion for hours.
Frequently asked questions
Why does process.env.MY_VAR work in getServerSideProps but not in my React component?
Because only variables prefixed with NEXT_PUBLIC_ are exposed to the client bundle. All other process.env.* access in browser JavaScript results in undefined.
Do I need to restart the dev server after changing .env files?
Yes. Next.js loads .env variables at startup. Any change requires a full restart to pick up new or updated values.
How do I fix environment variables not working after deployment?
Ensure variables are defined in your deployment provider's dashboard, use the NEXT_PUBLIC_ prefix for client access, and redeploy to rebuild with new env values.
Can I use process.env for secrets in client code?
No. Any variable with NEXT_PUBLIC_ is bundled into browser JS and is publicly readable. Never expose secrets this way.
How can I debug what environment variables are actually set during a build?
Add console.log(process.env) in getServerSideProps or an API route, then check build and runtime logs to see which variables are present.