Skip to content

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.env is a string, and a missing one is undefined. That is why ?? supplies a default, and why PORT goes through Number().
  • For yes/no settings, compare with the string: process.env.DEBUG === "true".
  • A .env file holds one NAME=value per 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.

More on Backend & APIs