Node.js environment variables and .env files
October 28, 2026 · 1 min read
Read a setting with process.env.NAME, add a default with ??, and load a .env file by running node --env-file=.env app.js (Node 22).
Read, default, load
Create app.js:
const port = Number(process.env.PORT ?? "3000");
const name = process.env.APP_NAME ?? "My App";
const debug = process.env.DEBUG === "true";
console.log({ port, name, debug });
Create a .env file next to it:
# local settings
PORT=4000
APP_NAME=Kettle Shop
Now run it three ways:
node app.js
# { port: 3000, name: 'My App', debug: false }
node --env-file=.env app.js
# { port: 4000, name: 'Kettle Shop', debug: false }
PORT=8080 node --env-file=.env app.js
# { port: 8080, name: 'Kettle Shop', debug: false }
What is happening
- Every value in
process.envis a string, and a missing one isundefined. That is why??supplies a default, and whyPORTgoes throughNumber(). - For yes/no settings, compare with the string:
process.env.DEBUG === "true". - A
.envfile holds oneNAME=valueper line, with#for comments. - A variable already set in your shell wins over the file, as the third run shows.
Common mistake
Committing .env. It often holds secrets such as API tokens. Add .env to .gitignore, and commit a .env.example with the variable names and harmless sample values instead.
Treating "false" as false. if (process.env.DEBUG) is true even when DEBUG=false, because the string "false" is not empty. Compare with === "true".
Takeaway
process.env gives you strings, so default them with ??, convert them yourself, and keep .env out of Git.