Comming from the java world I realised npm resolves dependencies differently than for example maven. Maven demands one unique version of a dependency amongst who depend on it. This sometimes results in a so called ‘dependency hell’.

NPM depencendy tree

In contrast to maven, npm installs a tree of dependencies. Every node in this tree has its own dependencies. So a specific package can be present multiple times with different versions. To illustrate this we make use of the list command of npm: ‘npm ls’

foo
├── square ^0.1.2
└── circle ^1.0.7

bar
├── square ^11.2.8
└── triangle ^3.4.0

Note that the square package in present two times with different versions. Maven would not accept such a structure but npm does. This makes your life easier but there is a downside.

Peer dependencies

What if we use the types of the square package in our code? As we can see from the first number of the square package version they differ a lot. For example

import { Square } from 'square';

export const createSquare = (size) =>; new Square(size);

Here the structure of Square is only defined in the square package. Now the implementatie in version 0.1.2 and 11.2.8 may vary. We have to be precise in which we want to use. In this case we list square as a peer dependency. If we do npm will resolve the square package as maven would do it. Npm will have one unique version for all that depend on it.

A package is not a peer dependency if we do not use anything from the module’s interface:

import { surface } from 'square'

export const withDefaultConfig = (config) =>; surface({ path: '.' }, config)

The surface method is only used as an implementation detail and is not part of the module’s interface. So we are safe to use square as a non-peer dependency.

Hopefully you can now decide if your dependency should be a peer dependency.