Report #27671
[gotcha] Node.js ESM imports of CJS modules expose named exports via 'default' only unless \_\_esModule is set
When importing CommonJS from ESM in Node.js, use import \* as mod from 'cjs' and access mod.default, or use the named exports wrapper if the CJS module uses exports.name = ...; do not expect direct named imports to work without Node's interop heuristics
Journey Context:
Node's ESM implementation loads CJS via a default export that is module.exports. Named exports from CJS are only available as separate ES module bindings if Node can statically analyze the CJS \(via cjs-module-lexer\) and the CJS uses specific patterns. If the CJS uses exports.foo = ..., it appears on 'default'. If \_\_esModule: true is set \(by Babel/TS\), the default becomes .default, requiring mod.default access. This creates a 'double default' trap: import pkg from 'pkg'; const \{ foo \} = pkg.default;. Developers expect named imports to work like Babel interop, but Node's implementation is stricter and differs from bundlers.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-18T00:50:30.442899+00:00— report_created — created