От 49 до 56% пакетов npm не имеют зависимостей вообще, а медиана по реестру — ноль. Так показали четыре независимые выборки, включая нашу контрольную. Среднее с апреля 2018 года не сдвинулось, хотя реестр вырос в 6,4 раза.
И вторая неожиданность: у typescript в дереве зависимостей 21 пакет, а устанавливается два. На этой разнице между «в замке́» и «на диске» построена половина пугающих цифр в теме.
Бесплатный онлайн-инструмент — проверка HTTP-заголовков: результат мгновенно, без регистрации.
Это первое, что стоит знать, и это противоречит расхожему образу. Мы отобрали случайные пакеты через реплику реестра и посмотрели поле зависимостей у последней версии каждого. Четыре независимых выборки:
| Выборка | Пакетов | Без зависимостей | Среднее прямых | Медиана |
|---|---|---|---|---|
| 1 | 615 | 49,1% | 3,01 | 1 |
| 2 | 936 | 50,3% | 3,02 | 0 |
| 3 | 1 077 | 52,3% | 2,53 | 0 |
| 4 (контрольная) | 45 | 56% | 2,00 | 0 |
Четыре набора, взятые независимо, дают 49–56% пакетов вовсе без зависимостей и медиану ноль. Среднее около двух-трёх — но среднее здесь малоинформативно, потому что распределение крайне скошено: p90 равен семи, p99 — двадцати семи, а максимум в выборках доходил до 99 и 367.
И зависимостей не становится больше. В апрельском срезе 2018 года среднее число прямых зависимостей составляло 2,8. Реестр с тех пор вырос в 6,4 раза, а среднее осталось там же. Разработчики объявляют не больше, чем раньше.
Оговорки: выборка берётся по алфавитным префиксам, а не строго равновероятно, поэтому соседние по алфавиту имена — часто из одного спам-семейства — представлены избыточно. Считаются только dependencies, без разработческих и необязательных.
Исходные данные всех таблиц этого отчёта доступны в виде открытого CSV-файла (UTF-8, первая строка — заголовки).
Скачать датасет (CSV)Это ловушка, на которой строится половина страшных цифр. Мы разрешили деревья через npm install --package-lock-only и сравнили с тем, что реально попадает на диск:
| Пакет | Своих прямых | В дереве | Установлено | На диске |
|---|---|---|---|---|
react 19.2 | 0 | 1 | 1 | меньше 1 МБ |
typescript 7.0 | 20 (все необязательные) | 21 | 2 | 30 МБ |
vite 8.2 | 5 | 40 | 16 | 28 МБ |
next 16.3 | 6 | 54 | 24 | 327 МБ |
express 5.2 | 28 | 68 | 68 | 3 МБ |
jest 30.4 | 4 | 322 | 182 | 43 МБ |
react-scripts 5.0 | 48 | 1 311 | 1 292 | 292 МБ |
У TypeScript в дереве 21 пакет, а ставится 2 — завышение в десять с половиной раз. Причина: современные инструменты публикуют по одному бинарнику на платформу как необязательные зависимости, а материализуется ровно один. Утверждение «у TypeScript теперь двадцать зависимостей» неверно: на вашей машине у него одна.
И число пакетов не связано с местом на диске. next ставит 24 пакета и занимает 327 МБ; react-scripts ставит 1 292 и занимает 292 МБ. В пятьдесят четыре раза больше пакетов — и меньше места.
Мы собрали типовые проекты с нуля. Числа зависят от выбранных ключей, и это само по себе показательно:
| Каркас | Объявлено | В дереве | Установлено | На диске |
|---|---|---|---|---|
| Next.js + React + TS + ESLint + Tailwind | 10–11 | 404 | 348 | 450 МБ |
| Тот же с другим набором ключей | 11 | — | 423 | 479 МБ |
| Vite + React + TS + ESLint | 8–9 | 134 | 110 | 75 МБ |
Разброс между двумя сборками одного каркаса — 348 против 423 — напоминание, что «сколько зависимостей у Next.js» вопрос без единственного ответа: он зависит от того, какие опции вы выбрали при создании проекта.
Самое важное в этой таблице — не абсолютные числа, а состав. 87% дерева Next.js — это разработческие зависимости, то есть инструментарий сборки, который в продакшен не едет. Глубина распределена так: на первом уровне 10 пакетов, на втором 61, на третьем 118, на четвёртом 107, дальше по убывающей до девятого. Средняя глубина 3,78, медианная 4.
Академический замер по срезу сентября 2023 года независимо пришёл к тому же: уязвимые пакеты чаще всего лежат на четвёртом-шестом уровне.
Мы разрешили деревья исторических версий тех же пакетов:
| Пакет | Пик | Сейчас | Изменение |
|---|---|---|---|
webpack | 395 в версии 3.12 (май 2018) | 68 | −83% |
react-scripts | 1 971 в версии 2.0 (сентябрь 2018) | 1 311 | −33% |
express | 86 в версии 5.0 (сентябрь 2024) | 68 | −21% |
Каждый достиг пика и с тех пор уменьшился. Современный каркас на Vite со своими 134 пакетами примерно вдесятеро легче сборки эпохи react-scripts.
Формулировка, которую данные поддерживают: «пик пройден в 2018–2020 годах, дальше консолидация на меньшем числе более крупных платформенных бинарников». Формулировку «раздувание всё хуже» данные не поддерживают.
| Цифра | Значение | Дата среза |
|---|---|---|
| Среднее прямых зависимостей | 2,8 | апрель 2018 |
| Среднее транзитивных | около 80 | апрель 2018 |
| Медиана: прямых / транзитивных | 2 / 21 | январь 2017 |
| Доля транзитивных рёбер графа | 94,7% | январь 2020 |
| Пакетов хотя бы с одной зависимостью | 61,3% | сентябрь 2023 |
Самая свежая из них — трёхлетней давности. Ни одного исследования графа зависимостей на срезе новее сентября 2023 года не существует, при том что реестр с апреля 2018-го вырос в 6,4 раза.
И критическая оговорка к цифре 94,7%: она посчитана только по рантайм-зависимостям, авторы прямо пишут, что разработческие и необязательные исключены. Поскольку в реальном дереве приложения разработческие составляют 87%, все такие оценки занижают то, чему разработчик доверяет на самом деле, почти на порядок.
«Средний проект npm тянет 79 транзитивных зависимостей». Здесь две ошибки сразу. Во-первых, это апрель 2018 года, а не 2025-й и не 2026-й. Во-вторых, 79 относится не к проекту, а к пакету: столько сторонних пакетов вы неявно начинаете доверять, устанавливая один средний пакет. Там же фигурирует и вторая величина, о которой почти не говорят, — 39 сопровождающих, то есть людей, которые могут этот код изменить. Её с 2018 года никто не перемерял.
«Проект на Next.js начинается с тысячи зависимостей». По нашему замеру — 404 в дереве и 348 установленных. Тысяча с лишним описывает эпоху react-scripts, снятого с поддержки в 2025 году.
«95% уязвимостей приходится на транзитивные зависимости». К npm это не прослеживается: ближайшее корректно измеренное — 94,7% рёбер графа зависимостей на срезе января 2020 года, а это совсем другая величина. Подробнее — в разборе цепочки поставок.
npm ls --all показывает то, что реально на диске.Источники: Zimmermann и др., USENIX Security 2019, Zerouali и др., EMSE 2022, Robinson и др., ASIA CCS 2026, реплика реестра npm.
Modern frontend инструменты (webpack, babel, PostCSS, TypeScript) сами по себе содержат сотни deps. Plus React + routing + state + forms + i18n.
Checks lockfile versions против GitHub Advisory Database. Reports vulnerable packages + recommended upgrades.
pnpm — content-addressable storage → shared across projects (save disk). Bun — Rust-based faster. Оба сохраняют npm semver.
depcheck для unused. Замените небольшие deps на native API (fetch, Date). Consider Deno (std library > npm).
Бесплатный тариф — 10 мониторов, проверки каждые 5 мин, без карты. Платные тарифы — интервал от 1 минуты и проверки из нескольких регионов.