Main property in package.json defines package entry point
You know your project's dependencies are installed under node_modules
directory. But, when you do require('lodash')
, how does Node know which file to load?
"How does Node know which file to read when loading a module?"
Module loading works in two phases
When loading a dependency, Node.js works in two phases. This is in contrast to loading a core node module with require('fs')
or a local module with require('./queue/mem.js')
. A dependency is loaded in two phases
- the right directory is looked up and
- the entry point within that directory is located.
Finding directory
The runtime looks up all directories that are on the path from the current file to the root of the file system. In each directory, Node checks if it contains a node_modules
directory. If it does, the runtime goes inside that directory to look for a sub-directory identical to the module identifier being required. Node tries this until it finds a hit, or as a last resort, it tries few global system directories.
Locating entry point
After finding the directory, Node tries a couple of strategies to determine the entry point of the package. The entry point is the file, whose module.exports
object is returned as the return value of a require()
-call.
First, Node looks for a package.json
file and checks if it contains a main
property. It will be used to point a file inside the package directory that will be the entry point. If main property does not exist, then Node tries in order index.js
, index.json
and index.node
.
- if
package.json
contains amain
property, then use that - if no
main
property, then try to loadindex.js
index.json
index.node
What does entry point look like for popular packages
What is done inside a package is up to the module authors. There are a couple of ways to organize the entry point to a package. Here's how some of the popular npm modules do it.
Package | Main property in package.json |
---|---|
lodash | "lodash.js" |
chalk | "source" |
react | |
request | "index.js" |
commander | "index" |
moment | "./moment.js" |
debug | "./src/index.js" |
tslib | "tslib.js" |
fs-extra | "./lib/index.js |
It can be seen that many packages define the main
property, and only a few leave it to the default lookup convention.
Semantic Versioning Cheatsheet
Learn the difference between caret (^) and tilde (~) in package.json.