A package.json
file often contains different types of dependencies. For example:
{ "name": "my-project", "dependencies": { "foo": "^1.0.0" }, "devDependencies": { "bar": "^1.2.1" }, "peerDependencies": { "baz": "^2.5.4" }, "optionalDependencies": { "boo": "^3.1.0" } }
What is the difference between these dependencies?
Dependencies are the packages that your project depends on. But dependencies may serve various purposes. For example, you may need a dependency to build your project, another to run it, another to test it, and so on.
For this reason, in a package.json
file, different types of dependencies are listed in different objects. Each object stands for a different type of dependency.
dependencies
ObjectThe dependencies
object specifies the packages that you need to run your code. For example React, Vue, Firebase, etc.
When you run npm install some-package
, npm installs the package and adds it to the dependencies
object in the package.json
file.
If you are working on someone else’s code (let’s say you cloned a repository from GitHub), and you run npm install
from the root folder of the project, npm will install all the dependencies that are listed in the dependencies
object.
devDependencies
ObjectThe devDependencies
object maps the packages that you will only need during the development of your project. You don’t need them to run your code in production. For example, a testing framework like Jest, or other utilities like ESLint.
When you run npm install some-package --save-dev
, npm installs the package and adds it to the devDependencies
object in the package.json
file.
If you run npm install
on a cloned repository, npm assumes that you are developing the project. That’s why it will also install all the dependencies listed in the devDependencies
object.
If you do not want to install devDependencies
you can use the --production
flag, like so:
npm install --production
The package manager will only install the dependencies listed in the dependencies
object.
peerDependencies
ObjectThe peerDependencies
object is a little different to the other dependencies.
For one, you only need peerDependencies
if you are developing your own plugin.
Let’s say you created a plugin called 'choco-chip-cookies'
. Your module is relying on 'peanut-butter'
, and your plugin is only compatible with v1 of 'peanut-butter'
.
{ "name": "choco-chip-cookies", "version": "1.3.5", "peerDependencies": { "peanut-butter": "1.x" } }
Adding peanut-butter
to the peerDependencies
object ensures that your package choco-chip-cookies
can only be installed along with the major version ‘1’ of the host package peanut-butter
.
According to the official npm documentation:
In npm versions 3 through 6,
peerDependencies
were not automatically installed, and would raise a warning if an invalid version of the peer dependency was found in the tree. As of npm v7,peerDependencies
are installed by default.
You can add dependencies to the peerDependencies
object by manually modifying the package.json file.
optionalDependencies
ObjectAs the name implies, optionalDependencies
are optional.
Let’s say you have a dependency that may be used, but you would like the package manager to proceed if it cannot be found or fails to install. In that case, you can add those dependencies in the optionalDependencies
object.
A good use case for optionalDependencies
is if you have a dependency that won’t necessarily work on every machine. But you should have a fallback plan in case the installation fails. An example for optionalDependencies
can be services like Watchman.
You can add dependencies to the optionalDependencies
object by manually modifying the package.json
file.