What you'll learn
- Say what an environment variable is and why the value lives outside your code
- Keep .env out of git and know what to do the day a secret gets committed anyway
- Commit a .env.example so teammates know which variables the app needs
- Predict which variables ship to the browser based on prefixes like PUBLIC_ and VITE_
- Validate required variables at boot instead of failing mid-request later
on this page
You’ve seen them everywhere: process.env.API_KEY, import.meta.env.PUBLIC_URL, .env files. But nobody explains what they actually are, why they exist, or how to not accidentally push your secrets to GitHub.
This guide covers all of it.
What is an environment variable?
An environment variable is a value stored outside your code that your code can read at runtime. Instead of this:
// Hardcoded: dangerous and inflexible
const apiKey = "sk_live_abc123xyz789supersecret";
You write this:
// Read from environment
const apiKey = process.env.STRIPE_API_KEY;
The actual value lives somewhere else: a .env file, your CI/CD system, or your hosting provider’s dashboard.
Why this matters
Three big reasons:
1. Security. Secrets hardcoded in source code get committed to Git and shared with anyone who has access to the repo. Environment variables stay out of Git.
2. Different values per environment. Your dev database URL is different from your production database URL. Environment variables let the same code behave differently in development, staging, and production.
3. Easy to rotate. If an API key is compromised, you update one value in your hosting provider’s dashboard, not a hundred files in your codebase.
The .env file
Most frameworks use a .env file for local development:
# .env
DATABASE_URL=postgres://localhost:5432/myapp
STRIPE_SECRET_KEY=sk_test_abc123
PUBLIC_API_BASE=https://api.example.com
Your framework (Vite, Next.js, Astro, etc.) reads this file automatically when you run npm run dev.
The .env.example file
Since .env is gitignored, new team members won’t know what variables are needed. The solution: commit a .env.example with fake placeholder values.
# .env.example: safe to commit, no real values
DATABASE_URL=postgres://localhost:5432/myapp_dev
STRIPE_SECRET_KEY=sk_test_your_key_here
PUBLIC_API_BASE=https://api.example.com
This is the team’s documentation for “what env vars does this app need?”
When someone clones the repo:
cp .env.example .env
# Then fill in the real values
Public vs private variables
Most frameworks distinguish between public (exposed to the browser) and private (server-only) variables.
In Astro:
# Available in browser JS, prefix PUBLIC_
PUBLIC_SITE_URL=https://raindev.fyi
# Server-only, never sent to browser
DATABASE_URL=postgres://...
STRIPE_SECRET_KEY=sk_live_...
In Vite/Vue/React:
# Available in browser, prefix VITE_
VITE_API_URL=https://api.example.com
# Not available in browser (no prefix)
SECRET_KEY=supersecret
In Next.js:
# Available in browser, prefix NEXT_PUBLIC_
NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX
# Server-only
DATABASE_URL=postgres://...
Setting env vars in production
In production, you don’t use a .env file. Instead, you set variables in your hosting provider’s dashboard:
- Vercel: Project Settings → Environment Variables
- Netlify: Site Settings → Environment Variables
- Railway / Render / Fly.io: their respective dashboards
These are injected into your build and runtime process securely. You never commit them.
Reading env vars in your code
Node.js / Astro (server-side):
const dbUrl = process.env.DATABASE_URL;
if (!dbUrl) throw new Error("DATABASE_URL is not set");
Astro (client or server):
const siteUrl = import.meta.env.PUBLIC_SITE_URL;
Validating at startup:
For critical variables, validate them when your app boots rather than failing at runtime when a request comes in:
// src/lib/env.ts
const requiredVars = ["DATABASE_URL", "STRIPE_SECRET_KEY"] as const;
for (const key of requiredVars) {
if (!process.env[key]) {
throw new Error(`Missing required environment variable: ${key}`);
}
}
export const env = {
databaseUrl: process.env.DATABASE_URL!,
stripeKey: process.env.STRIPE_SECRET_KEY!,
};
The most common mistakes
| Mistake | What happens | Fix |
|---|---|---|
Commit .env to Git | Secrets exposed publicly | Add to .gitignore, rotate keys |
Use NEXT_PUBLIC_ for a secret | Secret visible in browser bundle | Remove prefix, use server-side only |
No .env.example | Teammates don’t know what vars exist | Add .env.example with fake values |
| No validation on startup | App silently fails later | Validate required vars at boot |
| Different var names in prod | App works locally, breaks in prod | Match names exactly across environments |
Environment variables are one of those things that seem annoying until the day you accidentally leak a database password. Set them up right from the start.
The rest of the Dev Setup series
Environment variables are one piece of turning your machine and your projects into something production-ready. The rest of the series:
- The terminal without fear: the commands you actually use, plus paths and flags.
- VS Code setup: extensions, format on save, and settings that match your project.
- Package managers: npm, pnpm, Yarn, and why lockfiles matter.
- Node versions: pinning Node so your app does not explode on another machine.
- Dotfiles: the config files that keep a project consistent across machines.
- ESLint and Prettier: a linter and a formatter, and why they sometimes fight.
- Project scripts: turning a pile of commands into
npm run dev. - Local databases: running Postgres and Redis without crying.
- Debugging setup: logs, breakpoints, and reading the crime scene.
signal check
Can you answer these without scrolling back up?
-
You committed a .env file with real secrets. Is deleting it enough?
No. If a .env file with real secrets was ever committed, those secrets are compromised. Rotate them immediately and make sure .env is in .gitignore so it cannot happen again.
-
Is it safe to put an API secret in NEXT_PUBLIC_API_KEY?
No. Any variable with a public prefix like PUBLIC_, VITE_, or NEXT_PUBLIC_ ends up visible in your compiled JavaScript bundle, where anyone who views source can read it. Secrets belong in unprefixed server-only variables.
-
How do env vars get set in production if .env is never deployed?
You set them in the hosting provider's dashboard, like Vercel or Netlify under Environment Variables. They get injected into your build and runtime process securely, and you never commit them.
progress is stored in this browser only