The wrong dependency type bloats production images or breaks your library's users.
package.json has several dependency fields, each with different install behaviour:
dependencies: needed at runtime. Installed for your project and for anyone who installs your package.devDependencies: needed only to develop, build or test (TypeScript, test runners, linters, bundlers). Installed for your project, never for consumers of a published package. Skip them in production withnpm ci --omit=dev.peerDependencies: "I plug into a host package the consumer provides." A React component library declares"react": "^18 || ^19"as a peer instead of bundling its own React. Since npm 7, missing peers are installed automatically, and conflicting peer ranges fail withERESOLVE. Mark optional peers withpeerDependenciesMeta.optionalDependencies: installed if possible; a failure (e.g. a platform-specific native binary) does not fail the install. Your code must handle their absence.bundleDependencies: shipped inside your package tarball.
For bundled frontend apps the distinction is softer, since the bundler decides what ships; many teams still keep build tools in devDependencies for faster CI installs.
--legacy-peer-deps ignores peer dependencies entirely and --force overrides conflicts. Both hide real incompatibilities; prefer fixing versions or using overrides.
Example
{
"name": "@acme/react-charts",
"version": "2.0.0",
"dependencies": {
"d3-scale": "^4.0.2"
},
"peerDependencies": {
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"react-dom": { "optional": true }
},
"optionalDependencies": {
"fsevents": "^2.3.3"
},
"devDependencies": {
"react": "^19.2.0",
"typescript": "^5.9.0",
"vitest": "^4.0.0"
}
}Remember
- dependencies ship to consumers; devDependencies never do
- peerDependencies: the host provides it (React, plugins)
- optionalDependencies may fail to install
- Avoid
--legacy-peer-depsand--forceas permanent fixes
Watch out for
- Listing react as a regular dependency in a component library, causing two React copies.