Witam na mojej prywatnej stronie internetowej!
[If this is all Polish to you, click here: English]
Uwaga: z oczywistych powodów nie mogę zagwarantować swojej nieomylności, choć staram się o zgodność tego, co piszę, z Prawdą. Jest również oczywiste, że nie gwarantuję takiej zgodności w przypadku komentarzy. Umieszczenie linku do strony spoza niniejszego serwisu nie musi oznaczać, że podzielam poglądy autora tej strony, a jedynie, że uważam ją za wartościową z takich czy innych powodów.
Marcin ‘mbork’ Borkowski
The more I work with Node.js, the more I appreciate its built-in features. Supply chain attacks are a real thing and the more I can do without pulling in megabytes (or even kilobytes) of dependencies, the better.
For example, one of the very common patterns in Node applications are configs in .env files. The traditional way to digest them is to use dotenv, which admittedly has zero dependencies – but nowadays even that is not necessary. You can just run Node with --env-file .env, and the variables from .env will be loaded into process.env. (There is also --env-file-if-exists, which silently fails instead of throwing if the given file does not exist.) This works much like the dotenv package – if something is already in process.env, the value from the .env file is discarded, you can use comments (starting with #) in the .env file, etc. Even better, you can use --env-file more than one time, and a few .env files will be read in, with values in later files overriding values from the earlier ones. That way, you can have a general .env file and an .env.dev file with local overrides (although whether it’s a good practice is another question). You can also use this feature in a dotenv-like style where instead of a command-line option you call process.loadEnvFile at the beginning of your script. There is even util.parseEnv, which accepts a string and returns an object containing the key-value pairs resulting from its parsing.
One feature that sets this apart from dotenv is that you can use this to set variables that configure Node itself. For example, you can say
NODE_OPTIONS=--title=some-node-app
in .env, and when you run node --env-file .env your-app.js, ps
aux will show you some-node-app instead of node --env-file .env
your-app.js. As far as I know, this is something dotenv (which operates on a different level) cannot do.
This behavior has some quirks, though. Apparently parsing CLI arguments is not entirely consistent. I created this file:
console.log('process.argv:', process.argv)
console.log('NODE_OPTIONS:', process.env.NODE_OPTIONS)
console.log('SOME_OPTION:', process.env.SOME_OPTION)
setTimeout(() => {}, 10 * 1000)
and this .env fle:
SOME_OPTION=some option NODE_OPTIONS=--title=some-node-app
and said node --env-file .env test.js. Unsurprisingly, this is what I’ve got:
process.argv: [ '/usr/bin/node', '/.../test.js' ] NODE_OPTIONS: --title=some-node-app SOME_OPTION: some option
and $ pgrep -a node showed
1225363 some-node-app
So far, so good. But watch this:
$ node test.js --env-file .env process.argv: [ '/usr/bin/node', '/.../test.js', '--env-file', '.env' ] NODE_OPTIONS: undefined SOME_OPTION: undefined
So, Node treated –env-file .env as parameters to my script and not to Node itself (correctly) – but somehow still used it:
$ pgrep -a node 1226282 some-node-app
Why this happens I have no idea. I suspect it’s a weird (and hopefully harmless) bug in Node itself I plan to report.
Anyway, as you can see, you might not need dotenv anymore. In fact, thanks to this, my most recent project (which I will certainly blog about soon!) is a Node CLI tool with zero dependencies.
While at that, let me also mention another cool feature which landed in Node v25.0.0 (so it will be available in the next LTS version in a month or two). Prior to Node v25, you could console.log a regex and see this:
Since v25, the output has the regex colored:
How cool is that!?