TypeScript ESM on Node.js requires three specific settings working together: (1) `"type": "module"` in package.json, (2) `"module": "NodeNext"` and `"moduleResolution": "NodeNext"` in tsconfig.json, (3) all relative imports must use `.js` file extensions (not `.ts`), even though source files are `.ts`. This is the most common confusion. For bundler-based projects (esbuild, Rollup), use `"module": "ESNext"` and `"moduleResolution": "Bundler"` instead.
"type": "module" in package.json"module": "NodeNext" in tsconfig"moduleResolution": "NodeNext" in tsconfig