npm WARN requires a peer of X but none is installed: fix
Read the peer range npm prints, install it into your app with one command, and see why the same project installs cleanly on npm 7 and later.
TL;DR#
npm versions 3 to 6 do not install a package's peerDependencies. They print requires a peer of … but none is installed and leave the job to you. The fix is to install the peer into your project's dependencies, using the whole range npm prints, in quotes: npm install "jquery@1.9.1 - 3". Do not copy it into your own peerDependencies. On npm 7 and later the warning does not appear at all, because npm installs peer dependencies itself.
The warning, reproduced#
The Stack Overflow question this page answers comes from an Angular project that depended on Bootstrap 4.1.1. The same message was reproduced on 11 October 2026 in a throwaway node:14-alpine container, with a package.json that lists only Bootstrap:
v14.21.3
6.14.18
npm WARN bootstrap@4.1.1 requires a peer of jquery@1.9.1 - 3 but none is installed. You must install peer dependencies yourself.
npm WARN bootstrap@4.1.1 requires a peer of popper.js@^1.14.3 but none is installed. You must install peer dependencies yourself.The install itself exits with code 0, so a script that only checks npm install carries on. The tree is still incomplete, and npm ls says so with a non-zero exit code:
demo@1.0.0 /w/a
+-- bootstrap@4.1.1
+-- UNMET PEER DEPENDENCY jquery@1.9.1 - 3
`-- UNMET PEER DEPENDENCY popper.js@^1.14.3
npm ERR! peer dep missing: jquery@1.9.1 - 3, required by bootstrap@4.1.1
npm ERR! peer dep missing: popper.js@^1.14.3, required by bootstrap@4.1.1
exit=1Why npm leaves the peer to you#
A peer dependency is a package's way of saying "I run alongside this host, I do not bring my own copy". The npm documentation for peerDependencies in package.json describes the field as a way "to express the compatibility of your package with a host tool or library". Bootstrap 4.1.1 uses it for jQuery and Popper. The npm registry entry for that release lists exactly two peers and no regular dependencies:
4.1.1 {"jquery":"1.9.1 - 3","popper.js":"^1.14.3"} {}Whether npm installs those peers for you depends on the npm major version. The same package.json documentation says that npm versions 3 through 6 did not install peer dependencies automatically and only raised a warning, and that npm v7 and later install them by default.
So on npm 6 the warning is the whole mechanism: npm checks the range, finds nothing that matches, prints the line, and moves on. "You must install peer dependencies yourself" is literal.
Fix: install the peers into your app#
1. Read the range, not just the lower bound#
The accepted answer on the question runs npm install jquery@1.9.1 --save. That pins the oldest version the range allows. In the reproduction it installed exactly that release, npm printed a deprecation notice for it, and package.json received a caret range anchored on it:
npm WARN deprecated jquery@1.9.1: This version is deprecated. Please upgrade to the latest version or find support at https://www.herodevs.com/support/jquery-nes or https://tuxcare.com/lp/click-jquery-support/.
+ jquery@1.9.1
"dependencies": {
"bootstrap": "4.1.1",
"jquery": "^1.9.1"
}1.9.1 - 3 is a hyphen range: any version from 1.9.1 up to and including every 3.x release. A later answer on the same question gives the better command: pass the range itself, in quotes, so the shell does not split it on the spaces.
2. Install every peer npm named, in one command#
Bootstrap 4.1.1 asks for two peers, so install both. Fixing only jQuery leaves the Popper line in place:
npm install "jquery@1.9.1 - 3" "popper.js@^1.14.3"npm resolves each range to the highest matching published version and writes it to dependencies. On npm 6.14.18 that happened without any --save flag:
+ jquery@3.7.1
+ popper.js@1.16.1
added 2 packages from 3 contributors in 0.794s
"dependencies": {
"bootstrap": "4.1.1",
"jquery": "^3.7.1",
"popper.js": "^1.16.1"
}Note that jQuery resolved to 3.7.1, not to the newest jQuery on the registry. At the time of writing the registry's latest tag points to jQuery 4.0.0, which is outside Bootstrap 4's range. Passing the range is what keeps npm inside it.
3. Leave your own peerDependencies alone#
The question asks whether the peer belongs in the app's peerDependencies section. It does not. That section is for a package that will itself be installed into someone else's project, such as a plugin declaring its host. On npm 6 it does not help either: with jQuery declared as a peer of the app itself, npm 6.14.18 installed nothing more and simply added a second warning, this time naming the app:
npm WARN demo@1.0.0 requires a peer of jquery@1.9.1 - 3 but none is installed. You must install peer dependencies yourself.
npm WARN bootstrap@4.1.1 requires a peer of jquery@1.9.1 - 3 but none is installed. You must install peer dependencies yourself.npm 10.9.9 did install jQuery from that same root peerDependencies entry, so the trick only appears to work on a current npm, where the peer would have been installed anyway. Put the peer in dependencies, which is where the command above writes it and which every npm version honours.
Verify the fix#
Run npm ls and look for an exit code of 0 with every package resolved:
demo@1.0.0 /w/d
+-- bootstrap@4.1.1
+-- jquery@3.7.1
`-- popper.js@1.16.1
exit=0Then answer the source's second question, whether the build server needs the peer as well, by doing what a build server does. Delete node_modules and install from the lock file with npm ci:
added 3 packages in 0.221s
demo@1.0.0 /w/d
+-- bootstrap@4.1.1
+-- jquery@3.7.1
`-- popper.js@1.16.1Because the peers are now ordinary entries in package.json and package-lock.json, the clean install brings them back with no extra step. If your pipeline deploys with dev dependencies left out, keep the peers in dependencies, not devDependencies. The babel-node on Heroku page shows what a platform does to devDependencies once the build finishes.
One email a month — the latest explained errors
What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.
When "none is installed" is not true#
npm 6 prints the same sentence when the peer is installed but at a version outside the range. With jquery pinned to 4.0.0 next to Bootstrap 4.1.1 and Popper, npm 6.14.18 still reported:
npm WARN bootstrap@4.1.1 requires a peer of jquery@1.9.1 - 3 but none is installed. You must install peer dependencies yourself.
added 3 packages from 5 contributors in 2.001sSo if you are sure the package is in node_modules, compare its version with the range in the message. Here the cure is to step back to a version the range accepts, or to move to a Bootstrap major that no longer needs jQuery. The registry shows Bootstrap 5.3.8 declaring only @popperjs/core as a peer, but that is a migration of your markup and scripts, not a one-line install.
The same project on npm 7 and later#
Run the original package.json, Bootstrap alone, through Node 22.23.3 and npm 10.9.9 and the warning never appears. npm installs the peers itself, and npm ls --all lists them under the package that asked for them:
added 3 packages in 2s
demo@1.0.0 /w/a
`-- bootstrap@4.1.1
+-- jquery@3.7.1
`-- popper.js@1.16.1On disk they sit at the top of node_modules, and the lock file marks the jQuery entry as a peer that npm brought in:
"node_modules/jquery": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
"integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==",
"license": "MIT",
"peer": true
},Your package.json is left as it was. That is fine for a build, but if your own code imports jQuery, list it in dependencies anyway so the version is yours to choose.
Two things bring the old behaviour back on a current npm.
The legacy-peer-deps setting#
npm's own definition of legacy-peer-deps says it "Causes npm to completely ignore peerDependencies when building a package tree, as in npm versions 3 through 6." With it, npm 10.9.9 installed Bootstrap alone and npm ls failed again, this time with the ELSPROBLEMS code:
added 1 package in 518ms
demo@1.0.0 /w/b
`-- bootstrap@4.1.1
+-- UNMET DEPENDENCY jquery@1.9.1 - 3
`-- UNMET DEPENDENCY popper.js@^1.14.3
npm error code ELSPROBLEMS
npm error missing: jquery@1.9.1 - 3, required by bootstrap@4.1.1
npm error missing: popper.js@^1.14.3, required by bootstrap@4.1.1A lock file written under that setting also breaks npm ci on a server that does not use it, as the Firebase deploy page on missing lock file entries reproduces.
A version you pinned outside the range#
The jQuery 4.0.0 project that npm 6 only warned about is a hard stop on npm 10.9.9:
npm error code ERESOLVE
npm error ERESOLVE unable to resolve dependency tree
npm error Found: jquery@4.0.0
npm error Could not resolve dependency:
npm error peer jquery@"1.9.1 - 3" from bootstrap@4.1.1If your install now stops with ERESOLVE rather than a warning, read the two ranges npm prints and pick versions that satisfy both. The ERESOLVE page on a Firebase prerelease peer conflict works through one such case, where a release candidate falls outside a stable-only peer range.
The peer warning is one of several places where npm 6 and current npm disagree about the same package.json. The Invalid version page shows another: which commands reject a short version field changed between npm 6 and npm 8. When a project installs cleanly on one machine and warns or fails on another, npm -v on both is the first thing to compare, and on npm 6 the missing peer is yours to install, with the full range npm printed.
Further reading: Fix npm Conflicting peer dependency: react@16.14.0. Also see Fix dyld "missing symbol called" in Node on an M1 Mac. Also see Material UI install fails on React 18 or 19 (ERESOLVE): fix. Also see Fix nvm use "exit status 1: Access is denied" on Windows.
Frequently Asked Questions
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
Continue Reading
Fix npm WARN package.json: No repository field
The warning is informational and harmless. Silence it for good in an application, fill it in properly for a library, and know why modern npm no longer prints it.
npm ERR! Invalid version: "1" — make it full semver
Find which package.json carries the short version, rewrite it as major.minor.patch, and know which npm commands check the field on old and current npm.
Fix npm Conflicting peer dependency: react@16.14.0
Read the package refusing your installed React version, distinguish the alternative candidate from the selected version, and preserve a verifiable lock file.


