Going DeeperExtra· 35 min read

Environment Variables and Secrets

Keep database passwords and API keys out of your code by storing them in a .env file — and learn which values are safe to send to the browser.

What you will learn

  • Store secrets in a .env file and read them with process.env
  • Explain why secrets must never be hard-coded
  • Use the NEXTPUBLIC prefix only for values that are safe in the browser

Why not just put the key in the code?

Apps need secret values: a database password, a paid API key, a login secret. If you type these directly into your code and push to GitHub, anyone who sees your code sees your secrets — they could run up huge bills or steal your data. The fix is to keep secrets in a separate file that is never committed to Git: a .env file.

The .env file

An environment variable is a named value that lives outside your code, in the environment your app runs in. You list them in a file called .env in your project root, one NAME=value per line.

A .env file holds secrets, kept out of Git
# .env  (never commit this file)
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
STRIPE_SECRET_KEY=sk_live_51HxYz...

Note: Output (behaviour): Next.js automatically loads this file when it starts. The values are now available to your code, but the file itself stays on your machine and on your server — it is listed in .gitignore so it never reaches GitHub.

Reading a variable with process.env

In server code (a Server Component, Route Handler or Server Action) you read a value through the special process.env object, using the same name you wrote in the file.

Server code reads a secret from process.env
// app/api/charge/route.js  (server only)
export async function POST() {
  const key = process.env.STRIPE_SECRET_KEY;   // read the secret
  // ...use key to talk to Stripe...
  return Response.json({ ok: true });
}

Note: Output (behaviour): process.env.STRIPESECRETKEY gives you the value from the .env file. Because this code runs on the server, the secret is used there and never sent to the browser — exactly what you want for a secret key.

Server-only vs browser-safe: the NEXTPUBLIC rule

This is the one rule beginners must get right. By default, environment variables are server-only — they are never sent to the browser, which is perfect for secrets. But sometimes you need a value in the browser (like a public analytics ID that is not secret). To allow that, and only then, prefix the name with NEXT_PUBLIC_.

Only NEXTPUBLIC variables are sent to the browser
# .env
DATABASE_URL=postgresql://...          # server-only (secret)
NEXT_PUBLIC_SITE_NAME=CodingClave      # safe to expose to the browser

Note: Output (behaviour): process.env.DATABASEURL works only in server code; in the browser it is undefined (kept secret). process.env.NEXTPUBLICSITENAME works everywhere, including Client Components — because you opted in by adding the NEXTPUBLIC prefix.

NameWhere it worksUse for
DATABASE_URLServer onlySecrets: DB passwords, private API keys
NEXT_PUBLIC_SITE_NAMEServer and browserNon-secret values the browser needs

Adding and using a secret, step by step

Here is the whole process of bringing a new secret into your app safely:

  1. Create a .env file in your project root if you do not have one, and confirm .env is listed in .gitignore so it is never committed.
  2. Add the secret as a line, with no NEXT_PUBLIC_ prefix, for example STRIPE_SECRET_KEY=sk_live_....
  3. Restart the dev server (npm run dev) so Next.js loads the new value.
  4. In server code only — a Server Component, Route Handler or Server Action — read it with process.env.STRIPE_SECRET_KEY.
  5. When you deploy, add the same name and value in your host dashboard (on Vercel: Settings → Environment Variables), since the .env file does not travel with your code.

Watch out: Never put a secret behind NEXT_PUBLIC_. Anything with that prefix is baked into the JavaScript sent to every visitor, so a NEXT_PUBLIC_STRIPE_SECRET_KEY would hand your secret key to the whole world. Secrets stay without the prefix.

Tip: When you deploy, your .env file does not go with it. Add each variable in your host dashboard instead — on Vercel that is Settings → Environment Variables, which keeps production secrets safe on the server.

Q. You have a secret database password. How should it be named in .env so it is NOT exposed to the browser?

Answer: Plain variables (no prefix) are server-only and stay secret. The NEXTPUBLIC prefix sends a value to the browser, which would leak a secret — so passwords must NOT use it.

✍️ Practice

  1. Create a .env file with one server-only variable and read it in a Route Handler with process.env.
  2. Add a NEXT_PUBLIC_ variable and show it in a Client Component.

🏠 Homework

  1. Move a hard-coded API key from your code into a .env file, read it via process.env in server code, and confirm it is not visible in the browser.
Want to learn this with a mentor?

CodingClave runs guided, project-based training (28-day, 45-day & 6-month batches).

Explore Training →