Repository: nodejs/node
Pull request: doc: add new environment variables doc page

Hi all :wave: 

This PR at its core is an effort to provide a proper specification for `.env` files, my interest picked on this after working on https://github.com/nodejs/node/issues/58729 where a user was requesting support for INI sections, claiming that Node.js dotenv implementation is INI compatible (something that initially sounded like a good idea to me, but that I now think we should not strive for [^1]). 

[^1]: [INI files](https://en.wikipedia.org/wiki/INI_file) are their own thing, they share some similarities to `.env` files but nowhere online I saw libraries/tools claiming that their `.env` implementation was compatible or related to INI files whatsoever.

After poking around it seems evident to me that Node.js current stand on `.env` file is lukewarm and along the lines of ~"we do whatever dotenv does" (https://github.com/nodejs/node/issues/58807#issuecomment-3000158677).

I more or less agree with that statement; the Node.js dotenv implementation was born based on [dotenv](https://github.com/motdotla/dotenv/) and I think we should indeed start from what dotenv does[^2], but also evolve our implementation independently as it makes most sense to us and our users. These are for example the first things that for me come to mind when thinking of diverging from dotenv:
 - if there there is something dotenv doesn't have specs for (e.g. variable names) we should define whatever makes most sense for us and our users
 - if there are things that we think dotenv doesn't do great (for me that's the lack of validation for example) we should not shy away from improving things on our end just for fear of diverging from dotenv

(Basically what I am trying to say is that I don't think that our specs being "whatever dotenv" does is really doing us, or our users any favours)
___

I'd also like to note that the changes in this PR describe the spec that I'm proposing Node.js should follow, they __do not__ describe the current Node.js behaviors. My hope is to first land this, agreeing on the spec, and then go and fix the diverging behaviors (which would basically become bugs) in separate PRs.


[^2]: Many tools in the JS ecosystem use dotenv under the hood, some of the most noticeable (impactful) I've found online are [Vite](https://vite.dev/guide/env-and-mode.html#env-variables-and-modes), [Next.js](https://github.com/vercel/next.js/tree/07a6e5b588d1f8aea55b78c9abab076206fae3f5/packages/next-env), so our goal, in my opinion, should be to support them the best we can (so that they don't need to rely on third-party tooling for dotenv support).

___

Some resources I took inspiration from (no AIs involved in this PR! :no_good:):
- [A Complete Guide to the Bash Environment Variables](https://www.shell-tips.com/bash/environment-variables/#gsc.tab=0)
- [Dotenvy Dotev File Format](https://hexdocs.pm/dotenvy/dotenv-file-format.html)
- [Ruby's dotenv](https://github.com/bkeepers/dotenv)
- [Python-dotenv](https://github.com/bkeepers/dotenv)

___


Related: 
- https://github.com/nodejs/node/pull/54215 (showing again that we try to (sometimes a bit blindly) do whatever dotenv does)
- https://github.com/nodejs/node/issues/54134 (showing that not having our own specification for `.env` files can trigger long and unproductive discussions)

____

This PR superseeds https://github.com/nodejs/node/pull/52735 (details below) and invalidates https://github.com/nodejs/node/pull/58782 (explained above)

Fixes: https://github.com/nodejs/node/issues/58807

<details><summary>Why didn't I try to get `52735` landed instead</summary>

Regarding https://github.com/nodejs/node/pull/52735, I completely restarted the effort from scratch since I must say that I wasn't a huge fan of the changes there, my main issues there were: 

 - I think it was very perscriptive, introducing a "parsing specification":
 https://github.com/nodejs/node/blob/ce0154b27b38a17011c25f8ab830a7bea63b2c71/doc/api/process.md?plain=1#L2312
  instead of a `.env` specification
   (I don't think we should describe how Node.js processes `.env` files, but what the syntax for those files is)
   (For example in the PR there were lines like: ["The parser processes input until it finds a newline"](https://github.com/nodejs/node/blob/ce0154b27b38a17011c25f8ab830a7bea63b2c71/doc/api/process.md?plain=1#L2324), I really
   dislike this type of wording which seems to almost describe how Node.js internally processes these files instead of helping users understand the structure of those)
- I disagree with some bits like: 
https://github.com/nodejs/node/blob/ce0154b27b38a17011c25f8ab830a7bea63b2c71/doc/api/process.md?plain=1#L2326
That's the current behavior, but I would like not  to properly document it and actually to challenge that and encourage users not to provide garbage `.env` files (I am thinking of possibly adding more strict validation to the dotenv parsing?)
- The examples with assert seem to me like adding extra noise more than anything else
- Again something like https://github.com/nodejs/node/blob/ce0154b27b38a17011c25f8ab830a7bea63b2c71/doc/api/process.md?plain=1#L2393C2-L2393C18 should in my opinion ideally not be documented but fixed on our side
- The changes are all under `process.loadEnvFile`, but I think that dotenv deserves its own documentation (I personally don't think that a user, looking for a `.env` specification would think of looking for it in the `process` doc page)

So because of the above, my preference was to propose a completely different solution for this issue :sweat_smile: 

</details> 


Changed files:
filename: doc/api/cli.md
patch: @@ -842,7 +842,7 @@ node --entry-url 'file.ts?query#hash'
 node --entry-url 'data:text/javascript,console.log("Hello")'
 ```
 
-### `--env-file-if-exists=config`
+### `--env-file-if-exists=file`
 
 <!-- YAML
 added: v22.9.0
@@ -853,7 +853,7 @@ added: v22.9.0
 Behavior is the same as [`--env-file`][], but an error is not thrown if the file
 does not exist.
 
-### `--env-file=config`
+### `--env-file=file`
 
 <!-- YAML
 added: v20.6.0
@@ -3980,8 +3980,8 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12
 [`--cpu-prof-dir`]: #--cpu-prof-dir
 [`--diagnostic-dir`]: #--diagnostic-dirdirectory
 [`--disable-sigusr1`]: #--disable-sigusr1
-[`--env-file-if-exists`]: #--env-file-if-existsconfig
-[`--env-file`]: #--env-fileconfig
+[`--env-file-if-exists`]: #--env-file-if-existsfile
+[`--env-file`]: #--env-filefile
 [`--experimental-addon-modules`]: #--experimental-addon-modules
 [`--experimental-sea-config`]: single-executable-applications.md#generating-single-executable-preparation-blobs
 [`--experimental-wasm-modules`]: #--experimental-wasm-modules

filename: doc/api/environment_variables.md
patch: @@ -0,0 +1,156 @@
+# Environment Variables
+
+Environment variables are variables associated to the environment the Node.js process runs in.
+
+## CLI Environment Variables
+
+There is a set of environment variables that can be defined to customize the behavior of Node.js,
+for more details refer to the [CLI Environment Variables documentation][].
+
+## `process.env`
+
+The basic API for interacting with environment variables is `process.env`, it consists of an object
+with pre-populated user environment variables that can be modified and expanded.
+
+For more details refer to the [`process.env` documentation][].
+
+## DotEnv
+
+Set of utilities for dealing with additional environment variables defined in `.env` files.
+
+> Stability: 1.1 - Active development
+
+<!--introduced_in=v20.12.0-->
+
+### .env files
+
+`.env` files (also known as dotenv files) are files that define environment variables,
+which Node.js applications can then interact with (popularized by the [dotenv][] package).
+
+The following is an example of the content of a basic `.env` file:
+
+```text
+MY_VAR_A = "my variable A"
+MY_VAR_B = "my variable B"
+```
+
+This type of file is used in various different programming languages and platforms but there
+is no formal specification for it, therefore Node.js defines its own specification described below.
+
+A `.env` file is a file that contains key-value pairs, each pair is represented by a variable name
+followed by the equal sign (`=`) followed by a variable value.
+
+The name of such files is usually `.env` or it starts with `.env` (like for example `.env.dev` where
+`dev` indicates a specific target environment). This is the recommended naming scheme but it is not
+mandatory and dotenv files can have any arbitrary file name.
+
+#### Variable Names
+
+A valid variable name must contain only letters (uppercase or lowercase), digits and underscores
+(`_`) and it can't begin with a digit.
+
+More specifically a valid variable name must match the following regular expression:
+
+```text
+^[a-zA-Z_]+[a-zA-Z0-9_]*$
+```
+
+The recommended convention is to use capital letters with underscores and digits when necessary,
+but any variable name respecting the above definition will work just fine.
+
+For example, the following are some valid variable names: `MY_VAR`, `MY_VAR_1`, `my_var`, `my_var_1`,
+`myVar`, `My_Var123`, while these are instead not valid: `1_VAR`, `'my-var'`, `"my var"`, `VAR_#1`.
+
+#### Variable Values
+
+Variable values are comprised by any arbitrary text, which can optionally be wrapped inside
+single (`'`) or double (`"`) quotes.
+
+Quoted variables can span across multiple lines, while non quoted ones are restricted to a single line.
+
+Noting that when parsed by Node.js all values are interpreted as text, meaning that any value will
+result in a JavaScript string inside Node.js. For example the following values: `0`, `true` and
+`{ "hello": "world" }` will result in the literal strings `'0'`, `'true'` and `'{ "hello": "world" }'`
+instead of the number zero, the boolean `true` and an object with the `hello` property respectively.
+
+Examples of valid variables:
+
+```text
+MY_SIMPLE_VAR = a simple single line variable
+MY_EQUALS_VAR = "this variable contains an = sign!"
+MY_HASH_VAR = 'this variable contains a # symbol!'
+MY_MULTILINE_VAR = '
+this is a multiline variable containing
+two separate lines\nSorry, I meant three lines'
+```
+
+#### Spacing
+
+Leading and trailing whitespace characters around variable keys and values are ignored unless they
+are enclosed within quotes.
+
+For example:
+
+```text
+   MY_VAR_A   =    my variable a
+    MY_VAR_B   =    '   my variable b   '
+```
+
+will be treaded identically to:
+
+```text
+MY_VAR_A = my variable
+MY_VAR_B = '   my variable b   '
+```
+
+#### Comments
+
+Hash-tag (`#`) characters denote the beginning of a comment, meaning that the rest of the line
+will be completely ignored.
+
+Hash-tags found within quotes are however treated as any other standard character.
+
+For example:
+
+```text
+# This is a comment
+MY_VAR = my variable # This is also a comment
+MY_VAR_A = "# this is NOT a comment"
+```
+
+#### `export` prefixes
+
+The `export` keyword can optionally be added in front of variable declarations, such keyword will be completely ignored
+by all processing done on the file.
+
+This is useful so that the file can be sourced, without modifications, in shell terminals.
+
+Example:
+
+```text
+export MY_VAR = my variable
+```
+
+### CLI Options
+
+`.env` files can be used to populate the `process.env` object via one the following CLI options:
+
+* [`--env-file=file`][]
+
+* [`--env-file-if-exists=file`][]
+
+### Programmatic APIs
+
+There following two functions allow you to directly interact with `.env` files:
+
+* [`process.loadEnvFile`][] loads an `.env` file and populates `process.env` with its variables
+
+* [`util.parseEnv`][] parses the row content of an `.env` file and returns its value in an object
+
+[CLI Environment Variables documentation]: cli.md#environment-variables_1
+[`--env-file-if-exists=file`]: cli.md#--env-file-if-existsfile
+[`--env-file=file`]: cli.md#--env-filefile
+[`process.env` documentation]: process.md#processenv
+[`process.loadEnvFile`]: process.md#processloadenvfilepath
+[`util.parseEnv`]: util.md#utilparseenvcontent
+[dotenv]: https://github.com/motdotla/dotenv

filename: doc/api/index.md
patch: @@ -27,6 +27,7 @@
 * [Diagnostics Channel](diagnostics_channel.md)
 * [DNS](dns.md)
 * [Domain](domain.md)
+* [Environment Variables](environment_variables.md)
 * [Errors](errors.md)
 * [Events](events.md)
 * [File system](fs.md)

filename: doc/contributing/advocacy-ambassador-program.md
patch: @@ -268,7 +268,7 @@ with projects learning from one another and their users.
 | [testing source code](https://nodejs.org/api/test.html)                                               | [16.17.0](https://nodejs.org/en/blog/release/v16.17.0) | Stable as of 20.0.0                                                |
 | [watching source code](https://nodejs.org/api/cli.html#--watch)                                       | [16.19.0](https://nodejs.org/en/blog/release/v16.19.0) | Stable as of 20.13.0                                               |
 | [parsing arguments](https://nodejs.org/api/util.html#utilparseargsconfig)                             | [18.3.0](https://nodejs.org/en/blog/release/v18.3.0)   | Stable as of 20.0.0                                                |
-| [reading environment](https://nodejs.org/api/cli.html#--env-fileconfig)                               | [20.6.0](https://nodejs.org/en/blog/release/v20.6.0)   | Active Development                                                 |
+| [reading environment](https://nodejs.org/api/cli.html#--env-filefile)                                 | [20.6.0](https://nodejs.org/en/blog/release/v20.6.0)   | Active Development                                                 |
 | [styling output](https://nodejs.org/docs/latest-v22.x/api/util.html#utilstyletextformat-text-options) | [20.12.0](https://nodejs.org/en/blog/release/v20.12.0) | Stable, as of [22.13.0](https://github.com/nodejs/node/pull/56329) |
 | [run scripts](https://nodejs.org/docs/latest/api/cli.html#--run)                                      | [22.0.0](https://nodejs.org/en/blog/release/v22.0.0)   | Stable, as of 22.0.0                                               |
 | [run TypeScript](https://nodejs.org/api/cli.html#--experimental-strip-types)                          | [22.6.0](https://nodejs.org/en/blog/release/v22.6.0)   | Active Development                                                 |
@@ -281,7 +281,7 @@ with projects learning from one another and their users.
 * <https://nodejs.org/api/test.html>
 * <https://nodejs.org/api/cli.html#--watch>
 * <https://nodejs.org/api/util.html#utilparseargsconfig>
-* <https://nodejs.org/api/cli.html#--env-fileconfig>
+* <https://nodejs.org/api/cli.html#--env-filefile>
 * <https://nodejs.org/docs/latest-v22.x/api/util.html#utilstyletextformat-text-options>
 * <https://nodejs.org/api/cli.html#--run>
 * <https://nodejs.org/api/cli.html#--experimental-strip-types>