npm install | how it works
If you're new to npm, start here...
npm install downloads a package and it's dependencies.
npm install can be run with or without arguments.
When run without arguments, npm install downloads dependencies defined in a package.json file and generates a node_modules folder with the installed modules.
When run with arguments, npm install downloads specific modules to the node_modules folder.
The package.json file dictates what modules will get installed in the node_modules folder. It's important that npm install is run in the same location as the package.json file.
Let's look at some examples in more detail...
npm install (no arguments)
npm install npm i
Both of these commands do the same thing. Running npm install without arguments installs modules defined in the dependencies section of the package.json file.
It's important that npm install is run in the same directory as the package.json file.
The downloaded modules are placed in a node_modules folder in the same location as package.json.
npm install also generates a package-lock.json file. This file describes the exact dependency tree that was installed. This makes it easier for subsequent installs to use the exact same tree (regardless of intermediate dependency updates).
npm dependency resolution
What's this tree you ask? Remember that npm install downloads a package and any dependencies it relies on. Sometimes different packages require different versions of the same module.
This can lead to a situation where module A requires v1 of module C and module B requires v2 of module C. In this case, both versions of the same module C are installed in a tree like structure.
The order in which the dependencies are installed dictates this tree structure. For example, v1 of module C may get installed at the root level while v2 is installed as a nested dependency of module B.
The details behind how npm resolves dependencies is outside the scope of this article, but the package-lock.json file can help insure the exact tree is installed with subsequent installs.
npm install (with arguments)
npm install can be run with different arguments. Here are some of the more important ones to be aware of...
npm install (specified package)
npm install express
When npm install is run with a specified package argument, it installs the package in the existing node_modules directory.
You can optionally provide a specific version as well...
npm install firstname.lastname@example.org
When a version is not provided, npm automatically downloads the latest stable version.You can also specify several packages in the same command...
npm install express eslint mongo
This will install express, eslint, and mongo in a single command.
npm install (directory)
npm install myfolder
When a folder argument is specified, npm install downloads everything from the specified location to the original node_modules directory at the root of the project.
This assumes a myfolder sub-directory exists in the same location as package.json. Additionally, the myfolder has it's own package.json
npm install WILL NOT generate a new node_modules folder inside the sub-directory. Instead, the dependencies are hoisted to the root directory's node_modules folder.
npm install (from git)
npm install (with options)
In addition to arguments, npm install can be run with different options. Here are some of the more important ones to be aware of...
npm install (with --global)
npm install -g npm install --global
When run with --global or -g, npm install installs the package globally. This means the package is installed in two places. The first is at the root directory where package.json is defined. The second is the global node_modules folder on the user system.
As a general rule, you want to install packages globally when they will be reused across projects or when they provide executable commands from the CLI.
npm install (with --save)
npm install express --save
When run with --save, npm install modifies the package.json file to include the specified package as a dependency. In this case, the express package will be added as a dependency to package.json.
The --save option is important whenever you want future installs to include the specified package.
npm install (with --save-dev)
The --save-dev flag specifies that the package should be added to the devDependencies section of the package.json rather than the dependencies section.
npm dependencies vs devDependencies
So what's the difference? Packages included as devDependencies won't get installed when the optional --production flag is used. This makes it possible to exclude packages you only need for development.
For example, linters are popular for enforcing clean code but aren't necessary in production. You would include a linter package as a devDependency so you can run linters against your code locally without including it in a production build.
npm install (with --production)
npm install -p npm install --production
The --production flag specifies to exclude devDependencies from the install. This means any dependency listed under the devDependencies section of package.json won't get installed when this flag is present.