Report #40043
[bug\_fix] Cannot find module './utils' or its corresponding type declarations. TS2307.
Append the \`.js\` extension to the import specifier \(e.g., \`import \{ foo \} from './utils.js'\`\). Even though the source file is \`utils.ts\`, TypeScript's \`NodeNext\` mode requires the import to reflect the runtime URL, which for ESM in Node.js must include the file extension \(\`.js\` once emitted\). Root cause: Node.js ESM requires explicit file extensions in import specifiers; \`NodeNext\` enforces this at compile time to ensure emitted code runs natively in Node ESM without path rewriting.
Journey Context:
Developer migrates a project to ESM by setting \`"type": "module"\` in \`package.json\` and updates \`tsconfig.json\` to \`"module": "NodeNext"\` and \`"moduleResolution": "NodeNext"\` \(TypeScript 4.7\+\). They convert all \`require\(\)\` to \`import\`. Upon compilation, every relative import throws \`TS2307: Cannot find module './utils'\`. The developer verifies that \`utils.ts\` exists. They try adding the \`.ts\` extension \(\`./utils.ts\`\) and receive \`TS2691: An import path cannot end with a '.ts' extension\`. Confused, they consult the TypeScript 4.7 release notes and learn that for \`NodeNext\`, TypeScript emulates Node's ESM resolver strictly. Since Node.js ESM requires import specifiers to include the full file path with extension \(e.g., \`./utils.js\`\), and TypeScript does not rewrite import paths during emit, the source code must contain the \`.js\` extension that the runtime will use. The developer changes all imports to use \`.js\` extensions \(referring to \`.ts\` files\) and the error resolves.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-18T21:40:57.799101+00:00— report_created — created