I’ve been using npm for around 10 years now and got to learn a lot about it’s behaviors and features and still get a little surprised how often I meet developers that don’t know when to use
npm ci and what are the differences between running
npm ci and
npm install so let’s have a deep dive into both commands and try to better understand when to use one or the other.
First and foremost both commands are used to install dependencies that are described in the package.json file in a project using npm. So virtually you can use any of both and get similar results, but as I said you virtually get same results.
npm i and
Meaning: This is pretty straightforward, install means something will be installed.
How it works:
- it will install a specific package if a package name is set as a parameter (i.e.:
npm i typescriptwill install typescript) or all packages described in the
package.jsonfile in the first folder it find traversing directories from the current one upwards.
- it will resolve the dependency versions based on the version definition that can use leading characters
~that will allow versions with newer minor or patch versions considered “safe” for the project, usually based on the knowledge of the team about the release strategy of the dependency. (i.e.:
^1.0.0allows 1.x.x versions to be installed while
~1.0.0allow 1.0.x versions to be installed, if no character is preceding the version only the strict same version will be installed.)
- it will update the package-lock.json file with the latest definitions that meet the requirements above.
Meaning: CI means Cleans Install (although I’ve seen developers saying it is “Continuous Integration”) this is usually a misunderstanding based on the fact that both terms are used in npm documentation, and the CI meaning is not clarified there.
How it works:
- it will check if there is a node_modules folder and will delete it
- it will raise an error if package-lock.json does not match package.json
- it will not resolve dependencies versions as it will actually install the exact versions defined in package-lock.json (or npm-shrinkwrap.json)
There are three use cases for using those commands and I want to list them and explore a little bit each of them to understand which and when to use each of the two commands.
- Install a new package
To install a new package you can only do it by using
npm install package_name or one of the aliases (npm i / npm add) they will do exactly the same thing. This is a bit confusing because
yarn install and
yarn add are different things, but this is subject for another post.
2. Update dependencies
As much as possible you should update your dependencies and make sure you have an update strategy in place either to have known dependencies bugs fixed but also to get improvements like performance, developer ergonomics, standards and new features. As we saw in the
npm install section of this article it will update using the version definitions using the leading characters
^ (caret) or
~ (tilde). So in case you are looking to update dependencies your first choice should be
npm install to get the latest versions defined as “safe” in your package.json (as also
npm update to update to latest versions that are out of the so defined “safe” versions).
3. Install dependencies
In case you are looking for installing dependencies to run the app in a fast and consistent way you are looking for
npm ci. It is faster than
npm install (around 75% faster in a couple of tests I’ve run) and consistent because it will install the exact same versions defined in
package-lock.json. Definitely this is a must have for server environments, but also on developer environments in order to avoid issues because of inconsistent dependency installation. In addition, if you use
npm install in the server and get inconsistent behaviors it may be difficult to replicate locally as your only safe option would be to download the package-lock.json from the server as it will be updated each time you run the
npm install, if you try it locally the versions may have changed in the meantime or even be cached in another server which would raise an error when installing with
npm ci as the exact version would not be available on the server. (I’ve dealt in the past with projects using a Nexus Server as proxy and local environments were cached daily while the server was reaching directly the npm servers and getting a newer version of the library.)
|Scenario||npm ci||npm install|
|Install a new package||🚫||✅|
To the latest compatible version according to version definitions.
Installation to run the app based on the existing dependency tree