Categories
dependencies node.js npm package.json

What’s the difference between dependencies, devDependencies and peerDependencies in npm package.json file?

2623

This documentation answers my question very poorly. I didn’t understand those explanations. Can someone say in simpler words? Maybe with examples if it’s hard to choose simple words?

EDIT also added peerDependencies, which is closely related and might cause confusion.

4

  • 70

    Note there are also optionalDependencies now.

    Jun 4, 2016 at 18:50

  • 240

    @AidanFeldman “optionalDependencies” is my oxymoron of the day

    – Nick Bull

    Mar 19, 2018 at 15:56

  • 5

    npm documentation says: “dependencies”: Packages required by your application in production. “devDependencies”: Packages that are only needed for local development and testing. see link: docs.npmjs.com/…

    – Deke

    Sep 28, 2019 at 17:57

  • dependencies are the package references that are used by your library without which it cannot work and to be installed along with your library installation automatically. While looking at peerDependencies, npm will just throw a warning message in case the specified packages are not found in node modules. It will not install any package for you. For detailed explaination refer link: medium.com/p/16f43d6c7e45

    – Goofy

    Feb 2 at 11:07

2953

Summary of important behavior differences:

  • dependencies are installed on both:

    • npm install from a directory that contains package.json
    • npm install $package on any other directory
  • devDependencies are:

    • also installed on npm install on a directory that contains package.json, unless you pass the --production flag (go upvote Gayan Charith’s answer), or if the NODE_ENV=production environment variable is set
    • not installed on npm install "$package" on any other directory, unless you give it the --dev option.
    • are not installed transitively.
  • peerDependencies:

    • before 3.0: are always installed if missing, and raise an error if multiple incompatible versions of the dependency would be used by different dependencies.
    • expected to start on 3.0 (untested): give a warning if missing on npm install, and you have to solve the dependency yourself manually. When running, if the dependency is missing, you get an error (mentioned by @nextgentech) This explains it nicely: https://flaviocopes.com/npm-peer-dependencies/
    • in version 7 peerDependencies are automatically installed unless an upstream dependency conflict is present that cannot be automatically resolved
  • Transitivity (mentioned by Ben Hutchison):

    • dependencies are installed transitively: if A requires B, and B requires C, then C gets installed, otherwise, B could not work, and neither would A.

    • devDependencies is not installed transitively. E.g. we don’t need to test B to test A, so B’s testing dependencies can be left out.

Related options not discussed here:

devDependencies

dependencies are required to run, devDependencies only to develop, e.g.: unit tests, CoffeeScript to JavaScript transpilation, minification, …

If you are going to develop a package, you download it (e.g. via git clone), go to its root which contains package.json, and run:

npm install

Since you have the actual source, it is clear that you want to develop it, so by default, both dependencies (since you must, of course, run to develop) and devDependency dependencies are also installed.

If however, you are only an end user who just wants to install a package to use it, you will do from any directory:

npm install "$package"

In that case, you normally don’t want the development dependencies, so you just get what is needed to use the package: dependencies.

If you really want to install development packages in that case, you can set the dev configuration option to true, possibly from the command line as:

npm install "$package" --dev

The option is false by default since this is a much less common case.

peerDependencies

(Tested before 3.0)

Source: https://nodejs.org/en/blog/npm/peer-dependencies/

With regular dependencies, you can have multiple versions of the dependency: it’s simply installed inside the node_modules of the dependency.

E.g. if dependency1 and dependency2 both depend on dependency3 at different versions the project tree will look like:

root/node_modules/
                 |
                 +- dependency1/node_modules/
                 |                          |
                 |                          +- dependency3 v1.0/
                 |
                 |
                 +- dependency2/node_modules/
                                            |
                                            +- dependency3 v2.0/

Plugins, however, are packages that normally don’t require the other package, which is called the host in this context. Instead:

  • plugins are required by the host
  • plugins offer a standard interface that the host expects to find
  • only the host will be called directly by the user, so there must be a single version of it.

E.g. if dependency1 and dependency2 peer depend on dependency3, the project tree will look like:

root/node_modules/
                 |
                 +- dependency1/
                 |
                 +- dependency2/
                 |
                 +- dependency3 v1.0/

This happens even though you never mention dependency3 in your package.json file.

I think this is an instance of the Inversion of Control design pattern.

A prototypical example of peer dependencies is Grunt, the host, and its plugins.

For example, on a Grunt plugin like https://github.com/gruntjs/grunt-contrib-uglify, you will see that:

  • grunt is a peer-dependency
  • the only require('grunt') is under tests/: it’s not actually used by the program.

Then, when the user will use a plugin, he will implicitly require the plugin from the Gruntfile by adding a grunt.loadNpmTasks('grunt-contrib-uglify') line, but it’s grunt that the user will call directly.

This would not work then if each plugin required a different Grunt version.

Manual

I think the documentation answers the question quite well, maybe you are just not familiar enough with node / other package managers. I probably only understand it because I know a bit about Ruby bundler.

The key line is:

These things will be installed when doing npm link or npm install from the root of a package and can be managed like any other npm configuration parameter. See npm-config(7) for more on the topic.

And then under npm-config(7) find dev:

Default: false
Type: Boolean

Install dev-dependencies along with packages.

27

  • 8

    Ah. I see I’ve misunderstood. Your answer reads as though npm install package is a command you’d use to install all packages that are not dev dependencies, rather than what I now think you meant, which was ‘install the package called [package]’, which was how I thought it worked before reading this. If I were you I’d edit to say [package-name] which clearly shows that what you mean is ‘insert-name-here’.

    – Tom W

    Mar 18, 2014 at 12:39


  • 272

    This is great! I never realized, but this answer has taught me that the dependencies vs devDependencies difference is only applicable if you’re going to publish an npm package. If you’re just working on an application or site, it shouldn’t matter too much. Thanks!

    Aug 29, 2014 at 3:37

  • 6

    This post should be updated to reflect the changed peerDependencies behavior in the upcoming [email protected] From blog.npmjs.org/post/110924823920/npm-weekly-5: “We won’t be automatically downloading the peer dependency anymore. Instead, we’ll warn you if the peer dependency isn’t already installed. This requires you to resolve peerDependency conflicts yourself, manually, but in the long run this should make it less likely that you’ll end up in a tricky spot with your packages’ dependencies.”

    May 22, 2015 at 4:11


  • 13

    Also, devDependencies are not installed transitively by dependent packages. Example: package A depends on package B. Package B depends on package C, and B also devDepends on package D. If you run npm install from package A, you will get B and C but not D.

    Jan 23, 2016 at 5:31

  • 25

    It’s important to remark that devDependencies aren’t installed when NODE_ENV is set to production.

    Aug 4, 2018 at 19:23

600

If you do not want to install devDependencies you can use npm install --production

6

  • 1

    npm install –save is for software dependancy?

    Jul 27, 2015 at 9:50

  • 22

    npm install will install all dependencies. –save flag is used when you want to add the specific module to package.json too. ex:- npm install uglify –save will install uglify in your project folder and add uglify to project, package.json file.

    Sep 13, 2015 at 7:58

  • 7

    And because we’re talking devDependencies, you can use –save-dev to save the new module as a devDependency. Example: npm install uglify –save-dev

    – Mykaelos

    Sep 29, 2016 at 18:39

  • 23

    As of npm 5, the --save option is no longer necessary. If you do “npm install my-package”, it will add my-package as a dependency in your package.json file.

    Feb 23, 2018 at 22:58

  • 2

    As of npm 5, the –save option is no longer necessary. That’s great news! I hadn’t realized this before. I always found it annoying that most docs neglect the --save option when really it hardly ever makes sense not to save the fact you added a dependency.

    Jan 14, 2019 at 18:25

145

As an example, mocha would normally be a devDependency, since testing isn’t necessary in production, while express would be a dependency.

7

  • 5

    I would lean towards putting testing as a dependency since you may want to run self-tests before launching the production server

    – user9903

    Jan 10, 2014 at 22:08

  • 61

    I would instead recommend using a continuous integration service like Hudson or CircleCI that runs your tests and then deploys to production if they pass.

    – Dan Kohn

    Jan 12, 2014 at 13:57

  • 1

    It may still be relevant to test the actual server because the CI server might differ somehow from the prod server, and this difference may e.g. prevent the app from starting up…

    – Nicole

    Mar 25, 2016 at 22:33

  • 2

    @Nicole why would you make your staging server not identical in configuration to your prod?

    – Lucas

    Nov 20, 2017 at 15:57

  • 2

    Then again, adding test dependencies as regular dependencies introduces a whole bunch of extra libraries, each of which may fail in some way. I would lean (pun!) towards light-weight production servers with as little code on them as possible. Remember, the best code is no code!

    Jan 14, 2019 at 18:27