Environment Variables in JavaScript
Introduction
Environment variables configure apps per machine—ports, API keys, database URLs—without hard-coding secrets in source. Node exposes them via process.env. This chapter shows reading config, .env files in development, and safe deployment habits.
Prerequisites
process.env
// env.mjs
const port = Number(process.env.PORT ?? 3000);
const nodeEnv = process.env.NODE_ENV ?? "development";
console.log({ port, nodeEnv });Run with inline vars:
PORT=4000 NODE_ENV=production node env.mjsWindows PowerShell:
$env:PORT=4000; node env.mjsConvention: NODE_ENV
const isProd = process.env.NODE_ENV === "production";
if (isProd) {
console.log("strict logging, no debug traces");
} else {
console.log("dev mode");
}Libraries use this flag for optimizations and verbose errors.
.env Files (Development)
Teams often use the dotenv package locally:
npm install dotenv// load at top of entry file — dev only pattern
import "dotenv/config";
console.log(process.env.DATABASE_URL);Example .env (never commit secrets):
PORT=3000
DATABASE_URL=postgres://localhost:5432/appAdd .env to .gitignore. Provide .env.example with fake placeholders for teammates.
Warning
Do not commit API keys or production passwords. Use secret managers (cloud provider, Vault) in deployed environments—not flat files in git.
Validate Required Vars at Startup
function requireEnv(name) {
const value = process.env[name];
if (!value) throw new Error(`Missing env: ${name}`);
return value;
}
const apiKey = requireEnv("API_KEY");
console.log("key loaded, length", apiKey.length);Fail fast on boot instead of mid-request.
Config Module Pattern
// config.mjs
export const config = {
port: Number(process.env.PORT ?? 3000),
dbUrl: process.env.DATABASE_URL ?? "",
logLevel: process.env.LOG_LEVEL ?? "info",
};Import config once—avoid scattering process.env everywhere.
Mini Example: Server Port from Env
// server-env.mjs
import http from "node:http";
import { config } from "./config.mjs";
const server = http.createServer((req, res) => {
res.end(`running in ${process.env.NODE_ENV ?? "dev"}\n`);
});
server.listen(config.port, () => {
console.log(`listening on ${config.port}`);
});FAQ
Env vars are strings?
Yes—parse numbers and booleans explicitly.
Docker / PM2?
Pass env in compose files, Kubernetes manifests, or PM2 ecosystem config.
Client-side env?
Only NEXT_PUBLIC_* style vars are exposed to browsers in frameworks—never put private keys in front-end bundles.