Your AI coding agent reads an env variable that is undefined in the browser, and Next.js hides it on purpose

الجهد أقل من 10 دقائق تعديل الكود

AI coding agents read process.env.API_URL in client code, and Next.js returns undefined in the browser. Here is the NEXT_PUBLIC_ rule from the Next.js docs, why it freezes at build time, and the fix that keeps secrets safe.

انتقل إلى الإصلاح
في هذه الصفحة

Your AI coding agent wired up an analytics key, a Stripe publishable key or an API URL. It reads process.env.API_URL in a component, and in the browser the value is undefined. The .env file is right there, the server logs show the value, and the page still behaves as if the variable does not exist.

The cause is how Next.js decides which variables the browser may see, and the fix is a prefix plus a rebuild.

Why this happens

The Next.js docs say it plainly: variables without the NEXT_PUBLIC_ prefix “are only available in the Node.js environment, meaning they aren’t accessible to the browser.” The browser runs in a different environment from your server, so a plain process.env.API_URL in a Client Component has nothing to read.

To expose a value to the browser, Next.js inlines it at build time. In the docs’ words, it replaces references to process.env.[variable] in the JavaScript bundle with a hard-coded value, but only for variables prefixed with NEXT_PUBLIC_.

Agents trained on plain Node scripts and on other frameworks often write the bare name. They also tend to get three related things wrong:

  • Dynamic lookups are not inlined. The docs show that process.env[varName] and const env = process.env; env.NEXT_PUBLIC_X are not replaced, even with the right prefix. Only the literal form process.env.NEXT_PUBLIC_X works in browser code.
  • The value freezes at build time. After the build, per the docs, your app “will no longer respond to changes to these environment variables.” Editing the variable on your host and redeploying without a rebuild keeps the old value.
  • .env files under src/ are ignored. The docs say Next.js loads .env files from the project root only, not from the /src folder.

How to tell if this is your problem

  1. Find the failing read. Search the code for process.env. inside any file that starts with 'use client', or in any code that runs in the browser.
  2. Check the name. If it has no NEXT_PUBLIC_ prefix, that is the cause.
  3. If it does have the prefix and is still undefined, look for process.env[...] or a copied process.env object, then check that the .env file is in the project root and that the value existed when you last ran next build.

The fix

Rename the variable in your .env file and in the code:

NEXT_PUBLIC_API_URL=https://api.example.com
const url = process.env.NEXT_PUBLIC_API_URL

Then restart next dev, or run next build again for production. On a host such as Vercel or Netlify, set the variable in the host’s settings before the build runs, then trigger a new build, not just a redeploy of the old one.

Keep secrets on the server

Anything with the NEXT_PUBLIC_ prefix is written into JavaScript that every visitor downloads. Use it for values that are meant to be public, such as an analytics ID or a publishable key. Do not add the prefix to a secret key just to make an error go away. Instead, read the secret in a Server Component or Route Handler and pass the browser only the result.

If you need a value that changes after the build

The docs describe a runtime route: read the variable on the server during dynamic rendering. Calling await connection() from next/server before reading process.env.MY_VALUE opts the component into dynamic rendering, so the value is evaluated at request time. The docs note this lets one Docker image be promoted through several environments.

How to avoid this next time

Tell the agent up front: “In this Next.js app, browser code can only read variables named NEXT_PUBLIC_*, written as a literal process.env.NEXT_PUBLIC_NAME. Secrets stay in server code and are never given that prefix.” In review, search the diff for process.env in client files and confirm each name carries the prefix.

Comments