"Two flags that retire two ubiquitous npm packages. Most projects still install dotenv and nodemon in 2026 because their templates have for years. Stop."
--env-file — dotenv Without dotenv
The dotenv package has 30+ million weekly downloads. Its entire job is reading a .env file and putting its contents into process.env. Node 20 added a built-in:
# .env
DATABASE_URL=postgres://localhost/mydb
LOG_LEVEL=debug
API_KEY=sk-something-secret
node --env-file=.env script.mjs
# inside script.mjs, process.env.DATABASE_URL is set
Multiple --env-file flags stack — useful for layered configs:
node --env-file=.env --env-file=.env.local server.mjs
# .env.local overrides .env where keys collide
The format follows the dotenv convention: KEY=value per line, # for comments, quoted values for spaces. The implementation is a thin parser in Node's core; no need to install anything.
--watch — nodemon Without nodemon
nodemon watches your project and restarts Node on file change. Node 22 made --watch stable:
node --watch server.mjs
# Save server.mjs (or any imported module) → automatic restart
It walks the module graph from your entry file and watches every imported file. Edit a deep utility, and the server reloads. Save the entry file itself, same. Add --watch-path=./config to also watch directories not in the graph (e.g. config files loaded at runtime).
The Combined Dev Loop
node --env-file=.env --watch --enable-source-maps server.mjs--env-file=.env— loads environment--watch— restarts on file change--enable-source-maps— better stack traces (Node 22+ has this on by default in many configs)
"dev": "node --env-file=.env --watch server.mjs".What About .env.local, .env.production?
The convention from front-end frameworks (Next.js, Vite) loads multiple .env files in order: .env → .env.local → .env.production. Node's --env-file doesn't do this layering automatically — but you can stack flags:
# dev
node --env-file=.env --env-file=.env.local server.mjs
# prod (CI sets this command)
node --env-file=.env --env-file=.env.production server.mjs
For multi-environment setups, write a small wrapper that picks the right combination based on NODE_ENV. The flag itself doesn't pick policy for you — that's its strength (no surprises) and its limitation (you write the policy).
--watch vs Hot Module Replacement
Be clear what --watch does: it restarts the process on change. It does NOT do hot module replacement (HMR) — there's no surgical "reload this module's exports while the process keeps running." For frontend dev servers (Vite), HMR is the right tool. For backend servers, full restart is usually what you want: fresh state, no stale subscriptions, no leaked listeners. HMR for Node servers is rarely worth the complexity.
Pippa's Confession
require('dotenv').config() at the top of every entry. The runtime says what it does. The lesson: every dependency you can delete makes your project a little easier for next-Pippa to read.