How Node Resolves Modules (Paths, Exports, Conditions)
On this page
Why Module Resolution Matters
When you write import x from 'something', Node must determine which file to execute. Understanding resolution prevents mysterious runtime errors.
Relative vs Bare Imports
- Relative:
./file.js,../utils.js - Bare:
express,lodash
Relative Resolution
For relative paths, Node:
- Resolves the path from the current file.
- Checks for exact file match.
- Does NOT guess extensions in ESM.
Directory Resolution (CommonJS)
If you import a directory in CommonJS, Node looks for:
- package.json with a main field
- index.js
Example
require('./utils');
Node may resolve:
- ./utils.js
- ./utils/index.js
Node Modules Lookup
For bare imports, Node searches:
node_modules/
express/
package.json
If not found, it moves up parent directories.
package.json Fields
main: entry point for CommonJSexports: modern controlled entry points
Modern exports Field
{
"exports": {
".": "./dist/index.js"
}
}
This restricts what can be imported from your package.
ESM Resolution Differences
- File extensions required
- No automatic index resolution without explicit mapping
Resolution Debugging
Common errors:
- ERR_MODULE_NOT_FOUND
- Cannot find module
Production Insight
Resolution errors often occur when mixing ESM and CJS or misconfiguring package.json fields. Keep your module strategy consistent across the project.
Performance Consideration
Module resolution happens at startup. Poor structure increases cold start time in serverless environments.
Next Step
Next we will examine package.json in depth and understand how it controls project behavior.