TypeScript's Module Resolution Strategy
TypeScript's moduleResolution is the compiler's search plan for finding files behind import statements. It's crucial when mixing module types (ESM/CJS) or targeting Node.js vs. the browser. The footgun is assuming the default node works for modern ESM.
Why it exists
JavaScript code is split into files, or modules. When you write import { MyClass } from './utils', the TypeScript compiler needs to find the ./utils file to read its type information. Different environments like Node.js and web browsers have different rules for finding that file. The moduleResolution setting exists to tell TypeScript which set of rules to follow so its compile-time checks match the eventual runtime behavior.
The mental model
Think of moduleResolution as a detective's search plan. Given a clue (the import path, like 'lodash'), the strategy dictates the exact steps to find the target (the actual file on disk). Should it look for lodash.ts, lodash/index.ts, or check a package.json file for directions? The strategy defines this process, aiming to perfectly mirror how the runtime would find it.
How it works
TypeScript offers several strategies in tsconfig.json. The two most important are node and nodenext. The node strategy mimics the classic Node.js CommonJS (require()) algorithm: it checks for relative files, then traverses up the directory tree looking in node_modules folders. The nodenext strategy is for modern projects; it understands ECMAScript Modules (ESM) and new features like the exports field in package.json, which provides a map to a package's entry points.
When to use it
You always have a module resolution strategy, but you should explicitly set it to match your project's target. Use "moduleResolution": "node" for traditional CommonJS projects or web projects using a bundler that follows Node's logic. Use "nodenext" or "bundler" for modern Node.js projects using ESM or for bundlers that respect the exports field.
When not to use it
Avoid using a strategy that mismatches your runtime. For example, do not use the default node strategy if your Node.js project uses ESM ("type": "module" in package.json) and depends on packages that use the exports field. TypeScript won't find the correct module files, leading to compile-time "Cannot find module" errors that predict a crash at runtime.
One canonical example
Your code has import { a } from 'my-lib'. With "moduleResolution": "node", TypeScript looks for node_modules/my-lib/index.ts (and other variations). With "moduleResolution": "nodenext", it first checks node_modules/my-lib/package.json. If that file has an "exports" field pointing to "./dist/index.mjs", TypeScript knows to look there for the types, correctly modeling how a modern runtime would load the package.
Interview question
For a modern Node.js project that utilizes ECMAScript Modules (ESM) and relies on packages with 'exports' fields, which moduleResolution strategy should be configured?
- a.classic
- b.commonjs
- c.node
- d.nodenextCorrect
Why? this is the answer
The 'nodenext' strategy is specifically designed for modern Node.js projects using ESM and understanding the 'exports' field in package.json. The 'node' strategy, while a default, only mimics classic CommonJS resolution and would lead to 'Cannot find module' errors in this scenario.
Just read this? Test yourself on what you have been reading.
Read the original → typescriptlang.org
- #typescript
- #modules
- #compiler
- #tsconfig
Put your scrolling time to good use
Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on typescript — each one lists the topics its interview covers.
See open roles