Environment Variables
Keeping secrets out of your bundle while still making the values you actually need available in the browser.
阅读需 2 分钟
Almost every real app needs configuration that shouldn't be hardcoded — a database URL, an API key, a flag that differs between local development and production. Next.js has built-in support for .env files, but it also draws a firm, deliberate line between variables available on the server and variables available in the browser.
Loading variables from .env files
Create a .env.local file at the project root (next to package.json, not inside app/ or src/):
# .env.local
DATABASE_URL=postgres://localhost:5432/mydb
STRIPE_SECRET_KEY=sk_test_somethingNext.js loads these into process.env automatically — no extra package needed. You can read them anywhere that runs on the server: Server Components, Server Actions, Route Handlers, and proxy.ts.
// app/lib/db.ts
export async function connect() {
return createConnection(process.env.DATABASE_URL);
}create-next-app adds .env* to .gitignore by default — and it should stay that way. Anything in these files is meant to differ per environment and per developer, and a leaked API key committed to a public repository is one of the most common real-world security incidents.
Variables are server-only by default
This is the important part: a plain environment variable like DATABASE_URL above is available in server-side code, but Next.js strips it out of anything sent to the browser. If a Client Component tried to read process.env.STRIPE_SECRET_KEY, it would just get undefined — the actual value never makes it into the JavaScript bundle in the first place.
Exposing a variable to the browser deliberately
Sometimes the client genuinely needs a value — a public analytics ID, a publishable (not secret) API key. Prefixing the variable name with NEXT_PUBLIC_ tells Next.js to inline its value directly into the client bundle at build time:
# .env.local
NEXT_PUBLIC_ANALYTICS_ID=UA-000000-1"use client";
export default function Analytics() {
// Safe — this was always meant to be public
const id = process.env.NEXT_PUBLIC_ANALYTICS_ID;
return <script data-analytics-id={id} />;
}Never prefix an actual secret with NEXT_PUBLIC_ just to make a build error go away — that prefix is a promise to Next.js (and to anyone reading the code) that the value is safe for the entire internet to see, since it will be, literally, visible in your site's downloaded JavaScript.
Different files for different environments
.env.local is for local overrides and is never checked into git. .env.development and .env.production let you commit environment-specific non-secret defaults that differ between running next dev and a production build, layering underneath whatever .env.local provides. A typical setup keeps genuinely secret values out of any committed file entirely, injecting them instead through your hosting provider's own environment variable configuration at deploy time.
A quick mental check
Before adding NEXT_PUBLIC_ to anything, ask: "would I be comfortable with this value showing up in a browser's dev tools, visible to any visitor?" If the answer is no, it stays unprefixed and server-only — full stop.