fast parser diverges from the default parser (silent value loss)
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
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 stringThe 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
require('dotenv').parse('\fA=1') // { A: '1' }
require('dotenv').parse('\fA=1', {fast: true}) // {}
// same for \v and U+00A0The 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
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).
Source: motdotla/dotenv