#1043·dotenv

fast parser diverges from the default parser (silent value loss)

Author: chuanghiduocCreated Aug 23, 2026Updated Sep 3, 2026

name: fast parser diverges from the default parser (silent value loss with { fast: true }) about: parse(src, {fast:true}) returns different values than parse(src) for several inputs — including silently dropping values title: fast parser diverges from the default parser (silent value loss) labels: bug assignees: ''


The opt-in fast parser (parse(src, { fast: true }), merged in #1010) disagrees with the default regex parser on several classes of input. Since fast is meant as a drop-in performance option, any divergence means users who flip the flag get different env values — in one case a value is silently replaced with an empty string.

Reproduced on master (after #1041 and #1042), Node 24.12.0, Windows:

1. Blank line before a quoted multiline value — value lost

javascript
require('dotenv').parse('A=\n\n"hello\nworld"')
// default: { A: 'hello\nworld' }
require('dotenv').parse('A=\n\n"hello\nworld"', { fast: true })
// fast:   { A: '' }        <- secret silently becomes empty string

The default LINE regex lets \s* inside the quoted-value alternative span newlines, so a quote on a later line is consumed as A's value. The fast scanner ends A at end-of-line and then fails to parse "hello\nworld" as a key line.

This also fires without blank lines: A=\n'b' gives {A: 'b'} vs {A: ''}.

2. Form feed / vertical tab / non-breaking space before a key — key dropped

javascript
require('dotenv').parse('\fA=1')            // { A: '1' }
require('dotenv').parse('\fA=1', {fast: true}) // {}
// same for \v and U+00A0

The default parser skips these because \s matches them; the fast scanner only skips space/tab/newline/BOM, so when the key scan finds no [A-Za-z0-9_.-] it discards the whole line. NBSP is common in .env files edited via copy-paste.

3. Trailing junk after a closing quote — different value

javascript
require('dotenv').parse('TOKEN="abc" oops')
// default: { TOKEN: '"abc" oops' }
require('dotenv').parse('TOKEN="abc" oops', { fast: true })
// fast:   { TOKEN: 'abc' }

Default keeps everything after = (the junk falls outside the match), fast returns the clean quoted content. Arguably fast's result is nicer here, but it differs.


Tests demonstrating all five failures (tests/test-fast-parity.js, tap):

not ok 2 - fast must match default            (blank line case)
not ok 4 - fast drops key after "\f"
not ok 6 - fast drops key after "\u000b"
    ok - nbsp case folded into whitespace test
not ok - fast must match default              (trailing junk case)
# { total: 10, pass: 5, fail: 5 }

Happy to send a PR aligning the scanner with the default parser on all three (or at minimum cases 1–2, where data is lost or keys vanish).