Chapter 1 · Practice 2 of 6
Choose module and moduleResolution for the runtime that runs your code
Why it matters
Module settings tell TypeScript how imports are resolved at runtime. If they do not match reality, the compiler accepts imports that fail when the code runs, or rejects imports that would work.
- Code that Node.js runs directly (servers, CLIs, libraries): use
"module": "nodenext". TypeScript then follows Node's real rules for ESM and CommonJS, including required file extensions in ESM imports. - Code that a bundler builds (Vite, webpack, Next.js and similar): use
"moduleResolution": "bundler"with"module": "esnext"or"preserve". Bundlers allow extensionless imports andexportsconditions that Node alone does not.
The old moduleResolution: node (also called node10) and classic were deprecated in TypeScript 6.0 and are errors in TypeScript 7.0, as are module values amd, umd, systemjs and none. If an old project still uses them, moving to nodenext or bundler is the first step of any upgrade.
Do
- Use
nodenextfor anything Node.js loads without a bundler - Use
bundlerresolution for apps a bundler builds - Prefer
package.jsonsubpath imports (#/...) over custom aliases when Node runs the code
Avoid
- Keeping
moduleResolution: nodeornode10: it is an error in TypeScript 7 - Copying a tsconfig from a frontend app into a Node service unchanged