---
title: "dependencies vs devDependencies vs peerDependencies"
description:
  "Difference between dependencies, devDependencies and peerDependencies"
canonical_url: "https://www.bigbinary.com/blog/different-dependencies"
markdown_url: "https://www.bigbinary.com/blog/different-dependencies.md"
---

# dependencies vs devDependencies vs peerDependencies

Difference between dependencies, devDependencies and peerDependencies

- Author: Farhan CK
- Published: May 14, 2024
- Categories: ReactJS, npm

In a JavaScript project, understanding the distinctions between `dependencies`,
`devDependencies`, and `peerDependencies` is crucial for effective package
management. Each plays a distinct role in shaping how a project is built and
distributed. In this blog, we'll explore these terms and their differences.

## dependencies

The packages that are really needed for a project to function should be listed
under `dependencies`. These packages are always installed within that project.
If the project is also a package, then these dependencies will also get
installed in the host project that uses this package. Below are some common
examples of what might go under `dependencies`.

```json
 "dependencies": {
   "dayjs": "1.11.1",
   "immer": "^10.0.2",
   "ramda": "^0.29.0",
   "react": "^18.2.0"
 }
```

It's important to understand that the above packages do not always have to be
under `dependencies`. For example, if `dayjs` is needed only for development,
deployment or testing purposes, It should not be listed under `dependencies` but
rather in the `devDependencies` section, because `dependencies` will be bundled
with the main code, whereas `devDependencies` will not. So adding dependencies
that are only used in development purposes under `dependencies` is unnecessary
and will increase the bundle size, affecting the performance of the application.

To add a package to `dependencies` section, simply run:

```bash
yarn add package-name
```

If we are shipping a package, all our dependencies are installed in the root of
host projects `node_modules`. However, an exception occurs if the host project
already has the same dependency but with a different version. In this scenario,
that specific conflicting dependency will be installed within the `node_modules`
of our package to avoid version conflicts.

To explain it bit more lets say we have `dayjs@1.0.0` as one of our dependency
but the host project uses `2.0.0`. Then both versions will be installed, `2.0.0`
would be the in root `node_modules` and `1.0.0` in our package's `node_modules`.
This way, our package can continue to use `1.0.0` while the host uses `2.0.0`.
The folder structure of that host will look something like below.

```javascript {6,9}
host-project-app
├── src
│   └── index.js
├── node_modules
│   └── react
│   └── dayjs
│   └── my-awesome-lib
│     └── node_modules
│       └── dayjs
├── package.json
└── README.md
```

## devDependencies

Packages listed in `devDependencies` are used specifically for development
purposes. Any dependencies that do not go into our actual code are listed here
and not under `dependencies`. These dependencies won't be installed in a
production environment or in a host project if our project acts as a package.
Here are a few examples of what might belong in `devDependencies`.

```json
 "devDependencies": {
    "@babel/core": "^7.16.5",
    "eslint": "^8.41.0",
    "husky": "^7.0.4",
    "jest": "27.5.1",
    "prettier": "^2.8.8"
 }
```

Just like in `dependencies`, these packages may not always be in
`devDependencies`. For example, if we are building a package that enhances Jest
tests capabilities, then we should place `jest` under `dependencies`. Otherwise
our host project will break, because `jest` will not be installed in the host
project.

To add a package to `devDependencies` section, simply run:

```bash
yarn add -D package-name
```

## peerDependencies

`peerDependencies` are needed only if we are building a package. It allows host
to install any desired version unless we specify otherwise.

If we are using `yarn` as the package manager then `peerDependencies` are not
installed automatically. We have to install manually, even in our own package.
But there is a slight difference if you are using `npm`. Up to version 6 `npm`
does not install `peerDependencies` automatically. However, this changes from
version 7 onwards, as it will install `peerDependencies` automatically. So if we
are using `yarn` or `npm<=v6` and we have for example Storybook or Jest tests in
our package project, then we have to install `peerDependencies` as
`devDependencies`(not as `dependencies` which defeats the purpose) as well.

```json {7,10}
 "devDependencies": {
    "@babel/core": "^7.16.5",
    "eslint": "^8.41.0",
    "husky": "^7.0.4",
    "jest": "27.5.1",
    "prettier": "^2.8.8",
    "dayjs": "1.11.1",
 }
 "peerDependencies": {
    "dayjs": "latest"
 }
```

You might wonder about its purpose if manual installation is required. It serves
as a means for our package project to specify essential dependencies required
for the package to function properly. Simultaneously, it grants control to the
host project to choose which versions to install.

To add a package to `peerDependencies` section, simply run:

```bash
yarn add --peer package-name
```

Now the tricky part is determining whether a particular dependency should go
under `dependencies` or `peerDependencies`. Unfortunately, there is no clear
answer here. But there are some questions we can ask ourselves to narrow it
down.

1. If the specific version of the dependency is important for our package, that
   is if using a different version breaks our package, then definitely we want
   to place that package under `dependencies`.

   It is possible to place such dependencies under `peerDependencies` and
   specify supported versions like below, but it is not a good practice.

```json
 "peerDependencies": {
    "dayjs": "1.2.0 || 1.5.1",
 }
```

2. If the dependency is a widely used package like `react`, better place it
   under `peerDependency`and ensure that our package works with different
   version of that dependency. This way, the dependency installed in the host
   project can be reused by our package without installing a separate version.
3. If we want to make changes to a dependency in a manner that impacts its usage
   within the host project, then place it under `peerDependencies`. Good example
   of this is, at [neeto](https://www.neeto.com/) we have a package called
   `neeto-commons-frontend` which extracts numerous common functionalities
   utilized across various products. One such functionality is our error
   handling system, for which we use an
   [Axios interceptor](https://axios-http.com/docs/interceptors). To ensure the
   functionality of this interceptor, it's crucial to apply this interceptor to
   the same instance of Axios. To elaborate further, if we add Axios under
   `dependencies` in `neeto-commons-frontend`, but the host project uses a
   different Axios version, we will be making changes to the Axios instance
   that's in `node_modules` of `neeto-commons-frontend` and not of the host
   project, means the functionality will not work on the host project.

Another rationale behind utilizing `peerDependencies` is its substantial impact
on reducing the bundle size, particularly when bundling our package. Now if we
are using Rollup, placing certain packages under `peerDependencies` doesn't
automatically exclude them from the bundle. We need to explicitly specify this
in the Rollup configuration. This is achieved through the Rollup `external`
configuration option, where we provide a list of `peerDependencies` to be
excluded from the bundle. To simplify this process,
`rollup-plugin-peer-deps-external` automates the inclusion of `peerDependencies`
within the `external` configuration.

```js
import peerDepsExternal from "rollup-plugin-peer-deps-external";

export default {
  plugins: [
    // Preferably set as first plugin.
    peerDepsExternal(),
  ],
};
```

## Links

- [Human page](https://www.bigbinary.com/blog/different-dependencies)
