You use devDependencies incorrectly

In this article, I want to elaborate on things that belong to the dependencies section in package.json and the ones that should be in devDependencies.

npm logo

What do you mean by "incorrectly"?

When I ask a person why they installed Webpack with --save-dev, the most common response is "--save is only for what makes it into runtime while --save-dev is for development and build". However, they can't prove their point with anything other than the esthetic and logical distribution of packages. So, no practical advantages. The worst part about it is that major vendors also suggest installing their packages with that option. For example, different Webpack loaders:

Webpack css-loader installation instruction

What's the "correct" way?

Apart from dependencies and devDependencies in package.json, there's also an interesting --production option, made specifically for these sections.

For npm install:

npm install --production

For npm ci:

npm ci --production

Both of these commands install dependencies in the project but only from the dependencies section. Come to think of it, is there any sense in that if we can't do anything with packages from the dependencies section without the ones from devDependencies? Indeed, if we think about it in this way, there's no point in that flag.

In reality, there is, but under the condition of right use of --save and --save-dev. If a package is necessary for the production build, install it with --save. Otherwise use --save-dev. For example, we can't build for production without Webpack and Webpack CSS Loader, therefore they must be installed with --save. At the same time, Webpack Dev Server, Jest, or ESLint are not mandatory for the build, hence --save-dev.

The profit is, npm install --production and npm ci --production will not download spare dependencies, which aren't going to be used in the pipeline, during the building stage in CI . The benefits are obvious: it simply saves you build time, especially if you've got some bloated libraries in dev-dependencies that download (or even compile) binary files via postinstall.

Important to realise!

💡 The common misconception here is that you may think dependencies is for the project to work while in reality it's for the project to start working. No matter what makes it into runtime: package.json is far from being about that.

Some examples

Separating dependencies into regular and development dependencies is a common practice among package management tools for many languages that's significantly neglected in the JavaScript dev community.

For instance, a doc article at npmjs.org explains the meaning of this field in a very straight-forward way:

"devDependencies": Packages that are only needed for local development and testing.

If we take a look at a neighboring tool, Composer (package manager for PHP inspired by npm) also recommends to put packages for testing and alike into require-dev:

Lists packages required for developing this package, or running tests, etc. The dev requirements of the root package are installed by default. Both install or update support the --no-dev option that prevents dev dependencies from being installed.

So does Rust's Cargo with its [dev-dependencies]:

Sometimes there is a need to have dependencies for tests (examples, benchmarks) only. Such dependencies are added to Cargo.toml in the [dev-dependencies] section.

Are there any reasons to do it differently?

Why yes, you could find reasons to do things in a different way. This article's purpose is exactly for you to think about where you list your dependencies. Based on feedback, I noted two cases when it's possible to ignore these rules:

In case you are developing frontend with no backend, just backend, or CLI that will then be wrapped in pkg, then this article's principles will work perfectly.


The content of this text is food for thought on how to manage dependencies in npm. If you don't trust the author or straight-up don't understand what they're trying to say, try thinking about npm's --production flag and package.json's devDependencies on your own to come up with a conclusion.

ℹ️ The author rushed the article with a bold headline and forgot to cover many edgecases which cost them a bunch of comments. The text was extended several times in response to that. Thank you!