Skip to content
RU

How many dependencies an npm package and project has: four samples and live measurements

TL;DR. Between 49 and 56% of npm packages have no dependencies at all, and the registry median is zero.

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.

Check your site's headers →

Half of npm packages have no dependencies at all

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:

SamplePackagesZero dependenciesMean directMedian
161549.1%3.011
293650.3%3.020
31,07752.3%2.530
4 (control)4556%2.000

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.

The lockfile count overstates what installs

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:

PackageOwn directIn the treeInstalledOn disk
react 19.2011under 1 MB
typescript 7.020 (all optional)21230 MB
vite 8.25401628 MB
next 16.365424327 MB
express 5.22868683 MB
jest 30.4432218243 MB
react-scripts 5.0481,3111,292292 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.

What a real scaffold actually pulls

We built typical projects from scratch. The numbers depend on the options chosen, which is itself telling:

ScaffoldDeclaredIn the treeInstalledOn disk
Next.js + React + TS + ESLint + Tailwind10–11404348450 MB
The same with different flags11423479 MB
Vite + React + TS + ESLint8–913411075 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.

The ever-worsening bloat story does not survive measurement

We resolved the trees of historical versions of the same packages:

PackagePeakNowChange
webpack395 at 3.12 (May 2018)68−83%
react-scripts1,971 at 2.0 (September 2018)1,311−33%
express86 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.

Published figures and their real dates

FigureValueSnapshot date
Mean direct dependencies2.8April 2018
Mean transitive dependenciesabout 80April 2018
Median: direct / transitive2 / 21January 2017
Share of transitive edges in the graph94.7%January 2020
Packages with at least one dependency61.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.

Three figures that get retold wrongly

"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.

What to do

  1. Count what installs, not lines in the lockfile. For TypeScript the difference is tenfold. npm ls --all shows what is genuinely on disk.
  2. Look at dev dependencies separately. They are 87% of the tree and zero of production. Installing without them changes the picture radically — and that is the quantity that matters for the attack surface of a running application.
  3. Count namespaces, not only packages. The number of independent parties you trust is closer to the namespace count than to the package count.
  4. Do not carry figures between "declared", "in the tree" and "installed". They are three different quantities, and substituting one for another is the source of most alarming headlines in this field.

Sources: Zimmermann et al., USENIX Security 2019, Zerouali et al., EMSE 2022, Robinson et al., ASIA CCS 2026, the npm registry replica.

Learn more

Frequently Asked Questions

Why is the median so high?

Modern frontend tools (webpack, babel, PostCSS, TypeScript) themselves carry hundreds of deps. Plus React + routing + state + forms + i18n.

What does npm audit do?

Checks lockfile versions against GitHub Advisory Database. Reports vulnerable packages + recommended upgrades.

Do pnpm/bun solve it?

pnpm — content-addressable storage → shared across projects (save disk). Bun — Rust-based, faster. Both preserve npm semver.

How to reduce?

depcheck for unused. Replace small deps with native APIs (fetch, Date). Consider Deno (std library > npm).

Try the live tool that powered this guide

Free plan — 10 monitors, checks every 5 min, no card required. Upgrade for 1-minute interval and multi-region monitoring.