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

javascript
// env.mjs
const port = Number(process.env.PORT ?? 3000);
const nodeEnv = process.env.NODE_ENV ?? "development";
 
console.log({ port, nodeEnv });

Run with inline vars:

bash
PORT=4000 NODE_ENV=production node env.mjs

Windows PowerShell:

powershell
$env:PORT=4000; node env.mjs

Convention: NODE_ENV

javascript
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:

bash
npm install dotenv
javascript
// load at top of entry file — dev only pattern
import "dotenv/config";
 
console.log(process.env.DATABASE_URL);

Example .env (never commit secrets):

plaintext
PORT=3000
DATABASE_URL=postgres://localhost:5432/app

Add .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

javascript
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

javascript
// 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

javascript
// 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.

What comes next?

Web security basics.