Between 49 and 56% of npm packages have no dependencies at all, and the registry median is zero. Four independent samples say so, including our own control. The mean has not moved since April 2018, though the registry has grown 6.4-fold.
And a second surprise: typescript resolves 21 packages in its tree and installs two. Half the alarming figures in this field rest on that gap between the lockfile and the disk.
Free online tool — HTTP header checker: instant results, no signup.
This is the first thing to know, and it contradicts the common picture. We drew random packages through the registry replica and read the dependency field of each one’s latest version. Four independent samples:
| Sample | Packages | Zero dependencies | Mean direct | Median |
|---|---|---|---|---|
| 1 | 615 | 49.1% | 3.01 | 1 |
| 2 | 936 | 50.3% | 3.02 | 0 |
| 3 | 1,077 | 52.3% | 2.53 | 0 |
| 4 (control) | 45 | 56% | 2.00 | 0 |
Four independently drawn sets give 49–56% of packages with no dependencies at all and a median of zero. The mean sits around two to three — but the mean says little here, because the distribution is sharply skewed: p90 is seven, p99 is twenty-seven, and the samples’ maxima reached 99 and 367.
And dependencies are not multiplying. In the April 2018 snapshot the mean number of direct dependencies was 2.8. The registry has grown 6.4-fold since, and the mean has not moved. Developers declare no more than they did.
Caveats: sampling runs on alphabetical prefixes rather than strictly uniformly, so alphabetically adjacent names — often from one spam family — are over-represented. Only dependencies are counted, without dev or optional ones.
This is the trap half the alarming figures rest on. We resolved trees with npm install --package-lock-only and compared against what actually lands on disk:
| Package | Own direct | In the tree | Installed | On disk |
|---|---|---|---|---|
react 19.2 | 0 | 1 | 1 | under 1 MB |
typescript 7.0 | 20 (all optional) | 21 | 2 | 30 MB |
vite 8.2 | 5 | 40 | 16 | 28 MB |
next 16.3 | 6 | 54 | 24 | 327 MB |
express 5.2 | 28 | 68 | 68 | 3 MB |
jest 30.4 | 4 | 322 | 182 | 43 MB |
react-scripts 5.0 | 48 | 1,311 | 1,292 | 292 MB |
TypeScript resolves 21 packages and installs 2 — a ten-and-a-half-fold overstatement. The cause: modern tooling publishes one binary per platform as optional dependencies, and exactly one materialises. The claim that "TypeScript now has twenty dependencies" is wrong; on your machine it has one.
And package count is unrelated to disk space. next installs 24 packages for 327 MB; react-scripts installs 1,292 for 292 MB. Fifty-four times more packages, and less space.
We built typical projects from scratch. The numbers depend on the options chosen, which is itself telling:
| Scaffold | Declared | In the tree | Installed | On disk |
|---|---|---|---|---|
| Next.js + React + TS + ESLint + Tailwind | 10–11 | 404 | 348 | 450 MB |
| The same with different flags | 11 | — | 423 | 479 MB |
| Vite + React + TS + ESLint | 8–9 | 134 | 110 | 75 MB |
The spread between two builds of one scaffold — 348 against 423 — is a reminder that "how many dependencies does Next.js have" has no single answer: it depends on the options chosen at project creation.
The most important thing in that table is not the absolute numbers but the composition. 87% of the Next.js tree is dev dependencies — build tooling that never reaches production. Depth is distributed as 10 packages at level one, 61 at two, 118 at three, 107 at four, tapering to level nine. Mean depth 3.78, median 4.
An academic measurement on a September 2023 snapshot arrived independently at the same place: vulnerable packages most often sit at levels four to six.
We resolved the trees of historical versions of the same packages:
| Package | Peak | Now | Change |
|---|---|---|---|
webpack | 395 at 3.12 (May 2018) | 68 | −83% |
react-scripts | 1,971 at 2.0 (September 2018) | 1,311 | −33% |
express | 86 at 5.0 (September 2024) | 68 | −21% |
Each peaked and has shrunk since. A modern Vite scaffold at 134 packages is roughly ten times lighter than its react-scripts-era equivalent.
The framing the data supports is "peaked in 2018–2020, now consolidating onto fewer but larger platform binaries". The framing "bloat keeps getting worse" it does not support.
| Figure | Value | Snapshot date |
|---|---|---|
| Mean direct dependencies | 2.8 | April 2018 |
| Mean transitive dependencies | about 80 | April 2018 |
| Median: direct / transitive | 2 / 21 | January 2017 |
| Share of transitive edges in the graph | 94.7% | January 2020 |
| Packages with at least one dependency | 61.3% | September 2023 |
The freshest is three years old. No study of the dependency graph exists on a snapshot newer than September 2023, while the registry has grown 6.4-fold since April 2018.
And a critical caveat on that 94.7%: it counts runtime dependencies only — the authors state outright that dev and optional ones are excluded. Since dev dependencies make up 87% of a real application tree, every such estimate understates what a developer actually trusts by close to an order of magnitude.
"The average npm project pulls in 79 transitive dependencies." Two errors at once. First, this is April 2018, not 2025 or 2026. Second, the 79 applies not to a project but to a package: that is how many third-party packages you implicitly begin trusting when you install one average package. The same work carries a second figure almost nobody quotes — 39 maintainers, the people who can change that code. Nobody has re-measured it since 2018.
"A Next.js project starts at a thousand dependencies." Our measurement: 404 in the tree, 348 installed. The thousand-plus figure describes the react-scripts era, deprecated in 2025.
"95% of vulnerabilities come from transitive dependencies." This does not trace to npm: the nearest properly measured figure is 94.7% of dependency graph edges on a January 2020 snapshot, which is a different quantity. More on this in our supply chain breakdown.
npm ls --all shows what is genuinely on disk.Sources: Zimmermann et al., USENIX Security 2019, Zerouali et al., EMSE 2022, Robinson et al., ASIA CCS 2026, the npm registry replica.
Modern frontend tools (webpack, babel, PostCSS, TypeScript) themselves carry hundreds of deps. Plus React + routing + state + forms + i18n.
Checks lockfile versions against GitHub Advisory Database. Reports vulnerable packages + recommended upgrades.
pnpm — content-addressable storage → shared across projects (save disk). Bun — Rust-based, faster. Both preserve npm semver.
depcheck for unused. Replace small deps with native APIs (fetch, Date). Consider Deno (std library > npm).
Free plan — 10 monitors, checks every 5 min, no card required. Upgrade for 1-minute interval and multi-region monitoring.