Scoring sheet
How we scored the best JavaScript package managers
Every score in The best JavaScript package managers: npm vs pnpm vs Yarn vs Bun comes from this sheet: the tools we considered, the scale for each criterion, and the evidence and date behind each score.
This sheet is the evidence behind every score in our ranking of the best JavaScript package managers. The question it answers: "npm vs pnpm vs Yarn vs Bun: which JavaScript package manager should I use?" It is written for a JavaScript or TypeScript developer choosing the package manager for a project or a team.
The field
We built the field from what people ask and what they are told. On 14 October 2026 we asked GPT, Claude, Gemini and Perplexity models, through their APIs with web search on, four questions, for 16 answers in all:
- "npm vs pnpm vs yarn vs bun: which JavaScript package manager should I use in 2026?"
- "Which JavaScript package manager is fastest?"
- "Should I switch from npm to pnpm or bun for my project?"
- "What is the best package manager for a JavaScript monorepo?"
All 16 answers named npm, pnpm and Bun, and 13 also named Yarn (the three that did not were answering the question about switching from npm to pnpm or Bun). We added the other tools a reader might ask about: those the answers or the pages they cite mention (Yarn Classic, jpm, Turborepo and Nx), and newer installers the answers did not mention (Deno's installer and vlt).
Must-haves, which filter the field rather than score it:
- It installs a Node.js project's dependencies from the npm registry, from its package.json.
- It is actively developed, not in maintenance only.
Scored: npm 12.2.0, pnpm 12.11.2, Yarn 4.18.1 and Bun 1.4.3, each the latest release on the npm registry on 14 October 2026. All four are free and open source.
| Skipped | Why |
|---|---|
| Yarn Classic (1.x) | In maintenance only (fails a must-have). The last release, 1.22.22, came out on 9 March 2024, and Yarn's docs recommend moving to Yarn 4. |
Yarn with nodeLinker: node-modules |
A setting of Yarn, not a separate tool. Measured and reported alongside; Yarn is scored in its default Plug'n'Play mode. |
| npm 10 (bundled with Node.js 22) | An older npm, measured as a reference only, because npm 12 does not officially support the Node.js 22.22.0 on our test machine. |
| Deno | A runtime first, whose installer is part of the Deno toolchain; deno install can also install a package.json project's npm dependencies. None of the 16 answers named it. We plan to test it at the next re-check, due in January 2027. |
| vlt | A newer package manager for npm registry projects (1.3.8 when we tested) that needs Node.js 22.22 or later. None of the 16 answers named it. First in line for the next re-check, due in January 2027. |
| jpm | Its own website was cited once in the 16 answers; no answer recommended it. We plan to look at it at the next re-check, due in January 2027. |
| Turborepo and Nx | Task runners for monorepos, not package managers (fails a must-have). They run on top of any of the four. |
Rubric
We set the criteria and weights at 20:40 UTC on 14 October 2026, while the install benchmark was running. Here is exactly what existed at that point:
- A one-round smoke run of the benchmark on the Vite project, in all four scenarios (20:31 to 20:33 UTC).
- The five scored rounds on the Vite project (20:33 to 20:40 UTC). So three of the nine scored speed cells per tool were in, including the Vite warm-cache cell that later led to the 0.5-second floor.
- A first run of the behavior fixtures, which finished at 20:29 UTC. We did not keep its output, so nothing here relies on it.
The fixture results scored below come from a re-run at 22:23 to 22:24 UTC, after the benchmark finished at 22:22 UTC, and the production builds ran from 22:31 to 22:36 UTC. We chose the criteria and weights for the reader's job; we cannot show that the early Vite numbers had no influence, which is why we list them here.
| Criterion | Weight | Why this weight |
|---|---|---|
| Install speed | 25 | The first thing people ask about, and it is paid on every clone, CI run and container build. Not higher, because a few seconds rarely decides a team's choice on its own. |
| Correctness and strictness | 20 | Phantom dependencies and broken peer trees are the bugs that pass locally and fail in CI or production. |
| Security defaults | 15 | Install-time scripts and freshly published malicious versions are the main supply-chain attack paths; what a tool does with no configuration is what most projects get. |
| Workspaces and monorepos | 15 | Many teams run a monorepo, and the tools differ most here. |
| Compatibility | 15 | Whether real projects install and build with no special setup is the cost of switching. |
| Disk use | 10 | Matters on laptops with many projects and in CI caches, rarely decisive. |
Price is not a criterion: all four are free and open source.
Every tool is scored on its defaults. An opt-in counts only where an anchor says so. Yarn is scored in its default Plug'n'Play mode; its node-modules mode is measured and reported alongside.
Anchors
Each checklist below is the scoring rule. The lines under it describe what a 10, a 7, a 4 and a 0 look like on that checklist.
Install speed (25)
Measured: median wall-clock seconds of five runs in three scenarios (cold cache and no lockfile; cold cache with the tool's own lockfile; warm cache with lockfile and no node_modules) on three projects, so nine cells per tool. In each cell, ratio = the tool's median divided by the fastest tool's median. Speed ratio = geometric mean of the nine ratios. Medians under 0.5 seconds count as 0.5 seconds (added after the results; see below).
score = 10 x (1 - log2(speed ratio) / 3), rounded to one decimal, floored at 0.
- 10: as fast as the fastest tool in every cell (ratio 1.0)
- 7: about 1.9 times the fastest on average
- 4: about 3.5 times the fastest on average
- 0: 8 times the fastest or slower on average
The "repeat install with everything in place" scenario is reported, not scored.
Correctness and strictness (20)
A checklist of observable results from our fixtures, 10 points in all:
-
Undeclared ("phantom") imports, CJS and ESM, in a single-package project: 4 if both fail by default; 3 if they fail by default only in workspaces; 2 if a documented, stable opt-in makes them fail; 0 if no option does.
-
A peer dependency conflict (react-dom 19 with react 18): 2 if the install errors or warns.
-
A missing peer dependency (react-dom without react): 2 if it is installed automatically or the install fails; 1 if the install only warns and leaves a package that cannot load; 0 if silent.
-
A frozen-lockfile install fails when package.json no longer matches the lockfile: 2 if yes.
-
10: phantom imports fail by default, and every peer and lockfile case is handled
-
7: phantom imports fail only with a stable opt-in, a missing peer only warns and leaves a package that cannot load, and conflicts and lockfile drift are handled
-
4: no option blocks phantom imports, a missing peer is left silently, and conflicts and lockfile drift are handled
-
0: no strict layout, peer problems pass silently, and a frozen install does not catch drift
Security defaults (15)
A checklist, 10 points in all, each item verified by a fixture or the tool's own documentation (the table below says which):
-
Dependency lifecycle scripts (fixture with esbuild, core-js and unrs-resolver): 4 if blocked until the project approves each package; 3 if blocked except for a vendor-maintained allowlist; 0 if they run.
-
Release-age gate for newly published versions (fixture with react and openai): 2 if on by default; 1 if an opt-in exists.
-
Git and tarball-URL dependencies: 2 if blocked by default (at least for transitive dependencies); 1 if an opt-in allowlist exists; 0 if neither is documented.
-
A built-in vulnerability audit command: 1.
-
Lockfile entries re-checked against the registry on install by default (all installs or untrusted PRs): 1.
-
10: every protection above on by default
-
7: scripts blocked and most protections on
-
4: scripts blocked, little else
-
0: runs every install script and has no gates
Workspaces and monorepos (15)
A checklist, 10 points in all, from our workspace fixture and the documentation:
-
Workspaces link local packages: 1
-
workspace:protocol, so a local dependency can never resolve from the registry: 2 -
Runs a script across workspaces in dependency order (fixture: lib-a before app-b): 2
-
Selects workspaces by dependency graph (dependents or dependencies of a package): 2
-
Catalogs, one place for shared dependency versions: 2
-
Built-in repo-wide policy checks (for example constraints on versions or fields): 1
-
10: all of the above
-
7: linking, the workspace protocol, dependency-ordered runs and graph selection, but no catalogs or policy checks
-
4: linking, one of the 2-point features and policy checks (1 + 2 + 1)
-
0: no workspace support
Compatibility (15)
10 points in all:
-
Each of the three projects installs with default settings and its production build succeeds: 2 per project; 1 if it needed one documented step (for example approving build scripts or changing the linker); 0 if it did not build.
-
Comes with Node.js, nothing else to install: 2. A separate install: 1.
-
Editors, scripts and tools work with no loader or SDK setup: 2; needs setup: 0.
-
10: every project builds with defaults, the tool ships with Node.js and needs no extra setup
-
7: two projects need one documented step each, the tool is a separate install, and no loader or SDK is needed
-
4: every project needs one documented step, the tool is a separate install, and editors or scripts need setup
-
0: no project builds, and editors or scripts need setup (a tool that is a separate install still gets 1 point, so 1 is the lowest score in practice)
Disk use (10)
Measured with du (allocated blocks, a hard-linked file counted once) after a warm install: the project folder plus the tool's cache or store, and the extra space a second copy of the same project adds when it shares that cache. Disk ratio = geometric mean, over the three projects, of (total for two copies plus cache) divided by the smallest tool's total.
score = 10 x (1 - log2(disk ratio) / 2), rounded to one decimal, floored at 0.
- 10: the smallest
- 7: about 1.5 times the smallest
- 4: about 2.3 times the smallest
- 0: 4 times the smallest or more
Rubric fix after the results (14 October 2026)
One change was made after the benchmark results were in, and it is recorded here rather than hidden. In the warm-cache cells Bun and pnpm finished the small Vite project in 0.02 and 0.07 seconds, so the ratio formula turned differences of a few hundredths of a second into ratios of up to 86 (npm) and 64 (Yarn) in a single cell, outweighing everything else in the geometric mean. A reader does not feel the difference between 0.02 and 1.2 seconds. The fix: medians under 0.5 seconds count as 0.5 seconds before the ratios are taken. Both versions are below.
| Tool | Speed ratio, no floor | Score, no floor | Speed ratio, 0.5 s floor | Score, 0.5 s floor (used) |
|---|---|---|---|---|
| npm 12 | 13.19 | 0.0 | 8.86 | 0.0 |
| pnpm 12 | 1.65 | 7.6 | 1.39 | 8.4 |
| Yarn 4 (PnP) | 6.97 | 0.7 | 4.68 | 2.6 |
| Bun 1.4 | 1.07 | 9.7 | 1.07 | 9.7 |
| Yarn 4 (node-modules, not scored) | 10.24 | 0.0 | 6.88 | 0.7 |
| npm 10 (not scored) | 13.54 | 0.0 | 9.10 | 0.0 |
The order is the same either way, but the floor matters for the close call at the top. Totals without the floor: pnpm 8.76 (shown as 8.8), Bun 8.645 (8.6), Yarn 6.565 (6.6), npm 4.89 (4.9). pnpm's lead over Bun is 0.115 without the floor and 0.315 with it.
Scores and evidence (14 October 2026)
Install speed and disk use come from the formulas above, applied to our timing and disk measurements. The checklists are scored from the logs of our behavior fixtures and production builds, and, where the tables say so, from the documentation linked in the cell.
Install speed
Median seconds of five runs, with the fastest and slowest run in brackets, and each scored tool's ratio to the fastest tool in that cell (with the 0.5 s floor). All runs were on Linux; every one of the 360 timed runs exited without an error.
Vite and React starter
| Scenario | npm 12 | pnpm 12 | Yarn 4 (PnP) | Bun 1.4 | Yarn 4 node-modules (not scored) | npm 10 (not scored) |
|---|---|---|---|---|---|---|
| Cold, no lockfile | 7.48 (7.26 to 15.28), ratio 5.78 | 1.29 (1.22 to 2.15), ratio 1.00 | 8.52 (8.17 to 9.70), ratio 6.58 | 1.84 (1.57 to 4.02), ratio 1.42 | 9.28 (8.33 to 13.02) | 11.94 (10.99 to 12.61) |
| Cold, lockfile | 2.12 (2.02 to 2.50), ratio 1.87 | 2.16 (2.12 to 2.19), ratio 1.91 | 3.64 (3.53 to 4.33), ratio 3.21 | 1.13 (1.12 to 1.17), ratio 1.00 | 4.02 (3.77 to 4.25) | 2.41 (2.36 to 2.60) |
| Warm, lockfile | 1.55 (1.38 to 1.65), ratio 3.10 | 0.07 (0.06 to 0.20), ratio 1.00 | 1.16 (1.06 to 1.32), ratio 2.31 | 0.02 (0.02 to 0.02), ratio 1.00 | 1.65 (1.46 to 1.83) | 1.81 (1.49 to 2.05) |
| Repeat (not scored) | 0.70 (0.61 to 0.87) | 0.02 (0.02 to 0.02) | 0.85 (0.83 to 0.87) | 0.01 (0.01 to 0.01) | 0.89 (0.82 to 0.94) | 0.59 (0.57 to 4.00) |
Next.js starter
| Scenario | npm 12 | pnpm 12 | Yarn 4 (PnP) | Bun 1.4 | Yarn 4 node-modules (not scored) | npm 10 (not scored) |
|---|---|---|---|---|---|---|
| Cold, no lockfile | 41.36 (39.70 to 47.61), ratio 8.20 | 9.02 (4.41 to 12.02), ratio 1.79 | 32.21 (29.88 to 42.14), ratio 6.39 | 5.04 (3.97 to 6.85), ratio 1.00 | 39.33 (34.66 to 58.73) | 41.17 (37.03 to 42.69) |
| Cold, lockfile | 23.09 (21.40 to 23.89), ratio 5.43 | 4.25 (4.21 to 4.29), ratio 1.00 | 15.08 (13.43 to 22.38), ratio 3.55 | 5.40 (4.26 to 6.61), ratio 1.27 | 20.99 (19.20 to 43.08) | 21.13 (20.55 to 21.52) |
| Warm, lockfile | 17.18 (15.55 to 20.69), ratio 34.36 | 0.70 (0.43 to 0.87), ratio 1.39 | 3.50 (3.07 to 4.15), ratio 7.01 | 0.39 (0.32 to 0.46), ratio 1.00 | 8.91 (8.27 to 9.98) | 14.60 (13.73 to 16.00) |
| Repeat (not scored) | 1.35 (1.24 to 1.77) | 0.02 (0.02 to 0.03) | 1.93 (1.71 to 2.10) | 0.02 (0.02 to 0.03) | 2.03 (2.00 to 2.13) | 1.24 (1.15 to 1.36) |
Docusaurus site
| Scenario | npm 12 | pnpm 12 | Yarn 4 (PnP) | Bun 1.4 | Yarn 4 node-modules (not scored) | npm 10 (not scored) |
|---|---|---|---|---|---|---|
| Cold, no lockfile | 106.78 (105.39 to 108.67), ratio 23.85 | 6.43 (4.42 to 8.45), ratio 1.44 | 43.16 (41.27 to 67.15), ratio 9.64 | 4.48 (4.08 to 12.82), ratio 1.00 | 50.04 (46.70 to 76.65) | 100.60 (94.03 to 101.38) |
| Cold, lockfile | 69.13 (68.61 to 71.88), ratio 16.52 | 6.28 (4.25 to 6.33), ratio 1.50 | 19.97 (19.52 to 51.42), ratio 4.77 | 4.18 (3.36 to 4.35), ratio 1.00 | 25.49 (24.95 to 50.15) | 60.52 (59.25 to 60.99) |
| Warm, lockfile | 16.56 (14.68 to 16.87), ratio 16.64 | 1.87 (1.11 to 2.40), ratio 1.88 | 3.03 (2.99 to 3.29), ratio 3.04 | 0.99 (0.76 to 1.46), ratio 1.00 | 8.79 (8.60 to 9.96) | 15.50 (13.42 to 15.90) |
| Repeat (not scored) | 4.67 (4.47 to 4.90) | 0.02 (0.02 to 0.02) | 1.77 (1.74 to 1.87) | 0.04 (0.04 to 0.04) | 2.16 (2.11 to 2.24) | 4.72 (4.48 to 4.75) |
Without the floor, only the two warm-cache cells where a median was under 0.5 seconds change: on the Vite starter the ratios become npm 86.17, pnpm 3.61, Yarn 64.17 and Bun 1.00, and on the Next.js starter npm 44.51, pnpm 1.80, Yarn 9.08 and Bun 1.00.
Speed ratios with the floor: npm 8.86, score 0; pnpm 1.39, score 8.4; Yarn 4.68, score 2.6; Bun 1.07, score 9.7.
Network speed varied during the run. A probe before each of the 60 rounds downloaded a 4.38 MB tarball at a median of 34.9 MB a second (slowest 0.51, fastest 53.7), and three probes were under 5 MB a second. Some of the slowest single runs line up with those dips (Yarn's 51.42 seconds in the Docusaurus cold-lockfile cell came right after a probe at 2.1 MB a second); others do not, so the probe does not catch every dip. That is why we score medians.
Correctness and strictness
All items from our fixtures.
| Item (points) | npm 12 | pnpm 12 | Yarn 4 PnP | Bun 1.4 |
|---|---|---|---|---|
| Phantom imports (4) | 2: hoisted by default, both imports work; stable opt-in --install-strategy=linked made both fail |
4: both fail | 4: both fail | 3: hoisted in a single package (both work); --linker isolated, the default for new workspaces, made both fail |
| Peer conflict (2) | 2: ERESOLVE, install fails |
2: warns | 2: warns | 2: warns |
| Missing peer (2) | 2: react installed, react-dom loads | 2: react-dom loads | 1: warns, react-dom fails with MODULE_NOT_FOUND |
2: react-dom loads |
| Frozen install on drift (2) | 2: npm ci fails |
2: fails | 2: --immutable fails |
2: fails |
| Score | 8 | 10 | 9 | 9 |
Security defaults
Script and release-age items are from our fixtures, with the default settings confirmed in the documentation; git and tarball, audit and lockfile items are from the documentation linked in each cell, because the git host was not reachable from our test machine.
| Item (points) | npm 12 | pnpm 12 | Yarn 4 | Bun 1.4 |
|---|---|---|---|---|
| Dependency scripts (4), fixture | 4: blocked until npm install-scripts approve; strace saw no install script run |
4: blocked, install exits 1 with ERR_PNPM_IGNORED_BUILDS |
4: blocked (enableScripts false since 4.14); none ran |
3: "Blocked 2 postinstalls" (core-js and unrs-resolver); strace saw no install script run. esbuild is on Bun's default trusted list and was neither blocked nor run. The allowlist is from Bun's documentation, not our fixture |
| Release-age gate (2), fixture | 1: min-release-age opt-in, default null; installed react 19.3.1 and openai 7.34.0 |
2: minimumReleaseAge 1,440 minutes by default; installed react 19.3.0 and openai 7.32.0 |
2: npmMinimalAgeGate one day by default (security page); react 19.3.0, openai 7.32.0 |
1: minimumReleaseAge opt-in; installed react 19.3.1 and openai 7.34.0 (published about 50 minutes earlier) |
| Git and tarball deps (2), documentation | 2: allow-git and allow-remote default to none |
2: blockExoticSubdeps true for transitive deps |
1: approvedGitRepositories allowlist is opt-in |
0: no documented default restriction or allowlist found |
| Audit command (1), documentation | 1: npm audit |
1: pnpm audit |
1: yarn npm audit |
1: bun audit |
| Lockfile re-checked by default (1), documentation | 0 | 1: lockfile entries verified against policies before a frozen install (trustLockfile false); our Vite runs printed "Lockfile passes supply-chain policies" |
1: hardened mode on by default for pull requests on public GitHub repositories | 0 |
| Score | 8 | 10 | 9 | 5 |
The openai half of the age fixture printed "not installed" for every tool because openai does not export package.json; the versions above were read from each tool's node_modules or lockfile after the run. openai 7.33.0 and 7.34.0 were published 16.6 hours and 50 minutes before the fixture ran (registry time field), so both were inside the one-day gate.
Bun's script fixture printed only a count. On 16 October 2026 we ran the same fixture again with the same Bun 1.4.3 to name the packages: bun pm untrusted listed core-js and unrs-resolver. Setting an empty trustedDependencies list, which replaces Bun's default list, made Bun report esbuild as blocked too, so esbuild is on that default list; with the default list its postinstall script still did not run.
Workspaces and monorepos
Linking, the protocol and dependency-ordered runs are from our two-package workspace fixture; graph selection, catalogs and policy checks are from the documentation linked in each cell.
| Item (points) | npm 12 | pnpm 12 | Yarn 4 | Bun 1.4 |
|---|---|---|---|---|
| Links local packages (1), fixture | 1 | 1 | 1 | 1 |
workspace: protocol (2), fixture |
0: EUNSUPPORTEDPROTOCOL |
2 | 2 | 2 |
| Dependency-ordered runs (2), fixture | 0: --workspaces built app-b before lib-a |
2: pnpm -r built lib-a first |
2: foreach -t built lib-a first |
2: --filter '*' built lib-a first |
| Graph selection (2), documentation | 0: names and paths only | 2: --filter app..., ...^ |
2: foreach --recursive --from, workspaces focus |
2: --filter with graph selectors |
| Catalogs (2), documentation | 0 | 2: catalogs | 2: since 4.10 | 2: catalogs |
| Repo-wide policy (1), documentation | 0 | 0 | 1: constraints | 0 |
| Score | 1 | 9 | 10 | 9 |
Yarn's fixture items were first run only with nodeLinker: node-modules, not the scored Plug'n'Play mode. On 16 October 2026 we ran the same fixture with Yarn 4.18.1 in Plug'n'Play mode: it installed with the workspace:* dependency, app-b loaded lib-a through Plug'n'Play, and yarn workspaces foreach -At run build built lib-a first. The score stands.
Compatibility
Builds are from our default-settings install and production build of each project; the Node.js row is from the Node.js release index.
| Item (points) | npm 12 | pnpm 12 | Yarn 4 PnP | Bun 1.4 |
|---|---|---|---|---|
| Vite builds with defaults (2) | 2 | 2 | 2 | 2 |
| Next.js builds with defaults (2) | 2 | 1: install exited 1 until pnpm approve-builds --all |
1: build failed under PnP, passed with nodeLinker: node-modules (see note) |
2 |
| Docusaurus builds with defaults (2) | 2 | 1: same approval step | 2 | 2 |
| Ships with Node.js (2) | 1: no Node.js release bundles npm 12; Node.js 26.12.0 and 24.22.0 come with npm 11, Node.js 22.23.3 with npm 10 | 1 | 1 | 1 |
| No loader or SDK setup (2) | 2 | 2 | 0: editors need Yarn's SDKs, plain node needs the PnP loader |
2 |
| Score | 9 | 7 | 6 | 9 |
Note on Yarn's Next.js point: the anchor allows 1 point for "changing the linker", but that step leaves Yarn's default Plug'n'Play mode, in which every tool is otherwise scored. With 0 points there, Yarn's compatibility would be 5 and its total 6.89 (shown as 6.9); its place would not change.
Disk use
Two copies plus cache, divided by the smallest tool's total, geometric mean over three projects (from our disk measurements on Linux): npm 1.77 (5.9), pnpm 1.06 (9.6), Yarn 1.24 (8.4), Bun 1.04 (9.7). Not scored: Yarn node-modules 2.25 (4.1), npm 10 2.39 (3.7).
| Two copies of a project plus the cache | npm 12 | pnpm 12 | Yarn 4 (PnP) | Bun 1.4 |
|---|---|---|---|---|
| Vite | 210 MB | 140 MB | 223 MB | 137 MB |
| Next.js | 1,125 MB | 659 MB | 769 MB | 651 MB |
| Docusaurus | 888 MB | 491 MB | 426 MB | 480 MB |
Totals
| Pick | Speed (25) | Correctness (20) | Security (15) | Workspaces (15) | Compatibility (15) | Disk (10) | Weighted total |
|---|---|---|---|---|---|---|---|
| pnpm | 8.4 | 10 | 10 | 9 | 7 | 9.6 | 8.96, shown as 9.0 |
| Bun | 9.7 | 9 | 5 | 9 | 9 | 9.7 | 8.645, shown as 8.6 |
| Yarn | 2.6 | 9 | 9 | 10 | 6 | 8.4 | 7.04, shown as 7.0 |
| npm | 0 | 8 | 8 | 1 | 9 | 5.9 | 4.89, shown as 4.9 |
Sensitivity
pnpm leads Bun by 0.315 before rounding (9.0 against 8.6 as shown). The lead comes from security defaults, where pnpm scores 10 against Bun's 5, worth 0.75 weighted points. With the floor, moving 5 points of weight from security defaults to compatibility puts Bun first (8.845 against 8.81), and so does moving 6 from security defaults to install speed (8.93 against 8.86; 5 points makes them tie at 8.88). Without the floor, 2 points from security defaults to either install speed or compatibility puts Bun first, and so would one more security point for Bun. A reader who cares mostly about speed and is willing to configure Bun's minimumReleaseAge should treat Bun as the pick, which is how the page presents it. Yarn trails Bun mainly on speed (2.6 against 9.7) and leads only on security (+4) and workspaces (+1), and npm trails Yarn on everything except compatibility (+3), so the lower two places need much larger weight changes to flip.
Corrections before publication (16 October 2026)
- npm's "Ships with Node.js" point was 2 in the first draft of this sheet. No Node.js release bundles npm 12, so it is now 1: npm's compatibility score fell from 10 to 9 and its total from 5.04 to 4.89. The order did not change.
- The rubric section first said the criteria and weights were set before any benchmark results existed and after the fixtures had run. The timestamps above show otherwise, and the section now says exactly what existed.
- The summary lines under the correctness, workspaces and compatibility checklists were reworded to match the checklists. No score changed because of that.