Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc: add environment variables specification #52735

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
222 changes: 222 additions & 0 deletions doc/api/process.md
Original file line number Diff line number Diff line change
Expand Up @@ -2309,6 +2309,227 @@ import { loadEnvFile } from 'node:process';
loadEnvFile();
```

### Environment variables file parsing specification

This section describes how environment variables file parser reads a file
and sets up the environment variables in Node.js.
anonrig marked this conversation as resolved.
Show resolved Hide resolved
Comment on lines +2314 to +2315
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be reworded to:
This section describes how environment variables are read and parsed from a file.

While `.env` files descend from shell scripts that export environment
variables, there are important distinctions in how they handle quoting,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, instead of "they" vs "us", you can write it in way that speaks in general

spacing, and escaping values.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, you should list these items like so:
... various ____, such as ...

Additionally, the [Dotenv][] package has played a significant role in
IlyasShabi marked this conversation as resolved.
Show resolved Hide resolved
popularizing this format.

#### Basic parsing

* The parser processes input until it finds a newline, splitting each part into
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remember to use active sentence style, so wording like "Input data is processed ..." is preferred

a key and a value at the first `=` sign.
* Lines without an `=` are ignored.

```bash
BASIC=basic
WITHOUT_EQUAL
```

```cjs
const assert = require('node:assert');
const process = require('node:process');
assert.strictEqual(process.env.BASIC, 'basic');
assert.strictEqual(process.env.WITHOUT_EQUAL, undefined);
```

```mjs
import assert from 'node:assert';
import process from 'node:process';
assert.strictEqual(process.env.BASIC, 'basic');
assert.strictEqual(process.env.WITHOUT_EQUAL, undefined);
```

#### Whitespace handling

* Leading and trailing whitespaces characters around keys and values are
ignored unless they are enclosed within quotes.

```bash
SPACED_KEY = parsed
IlyasShabi marked this conversation as resolved.
Show resolved Hide resolved
```

```cjs
const assert = require('node:assert');
const process = require('node:process');
assert.strictEqual(process.env.SPACED_KEY, 'parsed');
```

```mjs
import assert from 'node:assert';
import process from 'node:process';
assert.strictEqual(process.env.SPACED_KEY, 'parsed');
```

#### Comments

* Lines starting with `#` are treated as comments and ignored.
* Inline comments (starting with `#` after a value) are ignored, and do not
Copy link
Member

@RedYetiDev RedYetiDev May 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are not inline comments, they are just comments

"A normal" // comment
"An inline" /* comment */ "can have more values afterward"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^^^

effect the parsed value.

```bash
# COMMENTS=work
INLINE_COMMENTS=inline comments # work
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

```

```cjs
const assert = require('node:assert');
const process = require('node:process');
assert.strictEqual(process.env.COMMENTS, undefined);
assert.strictEqual(process.env.INLINE_COMMENTS, 'inline comments');
```

```mjs
import assert from 'node:assert';
import process from 'node:process';
assert.strictEqual(process.env.COMMENTS, undefined);
assert.strictEqual(process.env.INLINE_COMMENTS, 'inline comments');
```

#### Empty values

* Variables with no value assigned (or example, a key followed by `=`) are set to
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"for" examples

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"for" example ...

an empty string.

```bash
EMPTY=
```

```cjs
const assert = require('node:assert');
const process = require('node:process');
assert.strictEqual(process.env.EMPTY, '');
```

```mjs
import assert from 'node:assert';
import process from 'node:process';
assert.strictEqual(process.env.EMPTY, '');
```

#### Quoted values

* Single (`'`), double (`"`), and backtick (`` ` ``) quotes are recognized.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this shouldn't be a bullet

The content within the quotes is taken as is, including leading and
trailing spaces.
* Quotes within a different quote type are preserved.

```bash
FIRST_NAME=' John '
MIXED_QUOTES="Say 'Hello!'"
BACKTICK_IN_QUOTES="Using `backticks` in double quotes"
```

```cjs
const assert = require('node:assert');
const process = require('node:process');
assert.strictEqual(process.env.FIRST_NAME, ' John ');
assert.strictEqual(process.env.MIXED_QUOTES, "Say 'Hello!'");
assert.strictEqual(process.env.BACKTICK_IN_QUOTES,
'Using `backticks` in double quotes');
```

```mjs
import assert from 'node:assert';
import process from 'node:process';
assert.strictEqual(process.env.FIRST_NAME, ' John ');
assert.strictEqual(process.env.MIXED_QUOTES, "Say 'Hello!'");
assert.strictEqual(process.env.BACKTICK_IN_QUOTES,
'Using `backticks` in double quotes');
```

#### Multiline values

* Values enclosed in quotes described above that span multiple
IlyasShabi marked this conversation as resolved.
Show resolved Hide resolved
lines are considered valid and includes escaped new line characters.

```bash
MULTI_DOUBLE_QUOTED="double
quoted"

MULTI_SINGLE_QUOTED='single
quoted'

MULTI_BACKTICKED=`this
"multiline"
value`
```

```cjs
const assert = require('node:assert');
const process = require('node:process');
assert.strictEqual(process.env.MULTI_DOUBLE_QUOTED, 'double\nquoted');
assert.strictEqual(process.env.MULTI_SINGLE_QUOTED, 'single\nquoted');
assert.strictEqual(process.env.MULTI_BACKTICKED,
'this\n"multiline"\nvalue');
```

```mjs
import assert from 'node:assert';
import process from 'node:process';
assert.strictEqual(process.env.MULTI_DOUBLE_QUOTED, 'double\nquoted');
assert.strictEqual(process.env.MULTI_SINGLE_QUOTED, 'single\nquoted');
assert.strictEqual(process.env.MULTI_BACKTICKED,
'this\n"multiline"\nvalue');
```

#### Escapes

* Newlines in double-quoted values are expanded to newline characters.
* Other escapes (e.g., `\n`) are treated as literal text in single-quoted
or unquoted values.

```bash
EXPAND_NEWLINES="expand\nnew\nlines"
DONT_EXPAND_UNQUOTED=dontexpand\nnewlines
DONT_EXPAND_SQUOTED='dontexpand\nnewlines'
```

```cjs
const assert = require('node:assert');
const process = require('node:process');
assert.strictEqual(process.env.EXPAND_NEWLINES, 'expand\nnew\nlines');
assert.strictEqual(process.env.DONT_EXPAND_UNQUOTED,
'dontexpand\\nnewlines');
assert.strictEqual(process.env.DONT_EXPAND_SQUOTED,
'dontexpand\\nnewlines');
Comment on lines +2493 to +2499
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, assertions shouldn't be used in the example, but rather just a comment explaining the item's value

```

```mjs
import assert from 'node:assert';
import process from 'node:process';
assert.strictEqual(process.env.EXPAND_NEWLINES, 'expand\nnew\nlines');
assert.strictEqual(process.env.DONT_EXPAND_UNQUOTED,
'dontexpand\\nnewlines');
assert.strictEqual(process.env.DONT_EXPAND_SQUOTED,
'dontexpand\\nnewlines');
```

#### Export statements

* Any `export` keyword before a key is ignored, allowing compatibility with
shell scripts. The line is parsed as if `export` weren't there.

```bash
export EXPORT_EXAMPLE = ignore export
```

```cjs
const assert = require('node:assert');
const process = require('node:process');
assert.strictEqual(process.env.EXPORT_EXAMPLE, 'ignore export');
```

```mjs
import assert from 'node:assert';
import process from 'node:process';
assert.strictEqual(process.env.EXPORT_EXAMPLE, 'ignore export');
```

## `process.mainModule`

<!-- YAML
Expand Down Expand Up @@ -3995,6 +4216,7 @@ cases:
[Android building]: https://github.com/nodejs/node/blob/HEAD/BUILDING.md#androidandroid-based-devices-eg-firefox-os
[Child Process]: child_process.md
[Cluster]: cluster.md
[Dotenv]: https://github.com/motdotla/dotenv
[Duplex]: stream.md#duplex-and-transform-streams
[Event Loop]: https://nodejs.org/en/learn/asynchronous-work/event-loop-timers-and-nexttick#understanding-processnexttick
[LTS]: https://github.com/nodejs/Release
Expand Down