Report #11069
[bug\_fix] Relative import paths need explicit file extensions in ECMAScript imports when '--moduleResolution' is 'node16' or 'nodenext'. Did you mean './utils.js'?
When using \`moduleResolution: 'Node16'\` or \`'NodeNext'\` with ES Modules \(\`'type': 'module'\` in package.json\), TypeScript requires the import path to include the \`.js\` extension, even though the source file is \`.ts\` \(e.g., \`import \{ foo \} from './utils.js'\`\). TypeScript will resolve the \`.js\` to the \`.ts\` source during type-checking, and the emitted JS will contain the correct \`.js\` extension required by Node.js ESM.
Journey Context:
A developer migrates a Node.js project to ESM by adding \`'type': 'module'\` to \`package.json\` and sets \`module: 'NodeNext'\` and \`moduleResolution: 'NodeNext'\` in \`tsconfig.json\` to properly support ESM. They write \`import \{ helper \} from './utils'\` where \`utils.ts\` exists. TypeScript immediately errors: 'Relative import paths need explicit file extensions... Did you mean './utils.js'?' The developer tries changing it to \`./utils.ts\`, but TypeScript says it cannot find the module. They are confused because they are writing TypeScript. They search and learn that for Node16/NodeNext ESM, they must write \`./utils.js\` in the source code, and TS will resolve it to the \`.ts\` file during type-checking and emit the \`.js\` extension in the output. They change the import to \`./utils.js\` and the error resolves.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T12:22:49.991980+00:00— report_created — created