So, every package.json has them — but how many people reading this are completely confident that all of their packages are in the right place, and what does that even mean anyway. I had a rough idea before, but had some issues in my work environment related to this so I decided to look into it and I hope that this information is useful to others.

In reality there are probably 3 dependency types that you will want to use (and only 2 if you are not making a library or npm package) — these are Dependencies, DevDependencies and PeerDependencies.

Now the brief summary of each is as follows:

Dependencies

These are packages that your application uses at runtime. Utilities, additional components or libraries / frameworks. Things like ramda, styled-components, react etc would go here. Infact this is usually the most obvious place to put packages.

However

DevDependencies

These are the packages that your application uses outside of its runtime. Its build tools, any dev tool scripts, unit tests and so on would go here. Things like babel (apart from runtime polyfills and such), jest, eslint et al would go here.

Peer Dependencies

This is where things get a little more tricky. If you are creating an npm package where you use a library, but either know or require the end package that will use your library to also need that dependency — you put your requirements in here. When the end package then installs your package — it will get warnings for any “unmet peer dependencies” and can then install them.

It is worth keeping in mind however that peer dependencies themselves are never installed (not since npm v2). This is the same for your own package. So say you write a new react component — and it uses hooks so it needs to be at least v16.8 — but you know that if you bundle your react version with your package, you get into issues with hooks and versioning (you can’t mount two versions of react easily) — so instead of having a dependency on 16.8.0 you would have a peer dependency of 16.8.0.

You publish, and consume your package — the end package gets the warning if they don’t have react already and all is well and good… until you try to work on your own published package.

DevDependencies (again!)

Without react being in your dependencies now its no longer being installed when you are working in your own package. So you will need to add react to the DevDependencies. Yep, that’s right — even though it is being used in runtime — its not a dependency — that is because we are expecting our end package to fulfill that requirement, and we don’t want to muck about with their versioning of react. So adding react as a dev-dependency here means we can Develop using a version of react (hence dev-dependency) — but publish and ship without that requirement.

TL;DR

When making npm libraries, use peer dependencies for packages your library depends on at runtime — and add these packages to your dev-dependencies for local development.