Build a production-shaped app
Protect environment values
Keep server configuration outside source control and understand exactly when a value becomes part of browser-visible code.
Next.js loads environment files for local work. Values without the NEXT_PUBLIC_ prefix stay server-only when used in server code.
The NEXT_PUBLIC_ prefix deliberately inlines a value into browser code at build time, so it must never hold a secret. The public value is frozen when the app is built. Promoting the same artifact to another environment does not replace it at runtime.
Keep .env.local ignored, provide a documented .env.example with names but no values, and configure real values in the deployment platform. Validate required configuration near the server entry point rather than failing deep inside a request.
// lib/server/config.ts
import 'server-only'
const notesApiToken = process.env.NOTES_API_TOKEN
if (!notesApiToken) throw new Error('NOTES_API_TOKEN is required')
export const serverConfig = { notesApiToken }
Add NOTES_API_TOKEN=dev-token-abc to .env.local and import serverConfig from a Server Component. The page should render. Remove the variable and restart dev: you should get NOTES_API_TOKEN is required at startup or first import, not a vague fetch failure later.
server-only turns an accidental Client Component import into a build error. It is a guardrail, not a vault. A value still leaks if server code renders it into HTML, passes it as a client prop, includes it in an error, or logs it somewhere other people can read.
Deliberately import the config module from a Client Component once to observe the failure, then remove the import. Search Git, HTML, client props, built JavaScript, and production logs for the token string.
Renaming a secret to NEXT_PUBLIC_NOTES_API_TOKEN will compile and then expose the value in the client bundle. Grep the built .next/static output for the string after every env change during review.
Production platforms inject env vars at runtime for server code, but NEXT_PUBLIC_ values still bake in at build time on most hosts. Set public vars in the build environment, not only at runtime.
Lesson completed