Next.js environment variables that end up in the browser
NEXT_PUBLIC_ values are inlined into the client bundle at build time. Server secrets stay unprefixed, in server code.
Next.js loads .env files into process.env for server code, including Route Handlers. A variable without the NEXT_PUBLIC_ prefix is not bundled for the browser. Prefix a name with NEXT_PUBLIC_ only when the browser is supposed to see the value.
Next.js replaces process.env.NEXT_PUBLIC_… with the literal string when you build, and that string ships in the JavaScript. Changing the variable later does not change a bundle that was already built. Rebuild and redeploy after you change a public value. A dynamic lookup such as process.env[name] is not inlined, which also means it will not hide a value the client bundle still needs.
Ways a secret still crosses over
- Do not put a database URL, a Stripe secret key, or a service role key in NEXT_PUBLIC_.
- Props you pass from a Server Component into a Client Component are sent to the browser. Do not pass a secret as a prop.
- A client component that imports a module which reads a secret pulls that read toward the browser. Keep secret reads in server modules.
- Do not commit a real secret in .env. The create-next-app template gitignores .env files. A value that was committed is still in history until you rotate it.
On the host, set secrets in the project environment and leave them unprefixed. The public site URL is a reasonable NEXT_PUBLIC_ value. An API secret is not.