Starters and boilerplates are how a lot of Node.js projects begin. You clone one, delete the parts you don't need, and start building. Whatever was in its package.json on that day becomes your baseline.
I wanted to know what that baseline looks like today, so I ran 26 well-known public starters through the same checks I built for deps.noticely.dev: known vulnerabilities from OSV.dev, deprecation and release history from the npm registry, and OpenSSF Scorecard from deps.dev.
The short version
Across 26 projects and 858 direct dependencies:
-
18 of 26 (69%) have at least one high or critical advisory that
npm installornpm updatewill not fix. The fixed version is outside whatpackage.jsonallows: either the version is pinned exactly, or the fix only exists in a newer major. 17 of those 18 have it in production dependencies, not just dev tooling. - 13 of 26 (50%) depend on at least one package its own authors have deprecated (62 such dependencies in total).
- 34% of all direct dependencies (288 of 858) have not had a release in more than two years.
- 49% of dependencies are at least one major version behind; 24% are three or more majors behind.
- Only 3 of 26 came out "Healthy". All three were updated in the last four months and commit a current npm lockfile.
How I counted
- Projects: 26 popular public Node.js starters, boilerplates and tutorial apps on GitHub, from 223 to 35k stars. The full list with per-project numbers is at the end.
-
What was checked: direct dependencies only, both
dependenciesanddevDependencies. Transitive dependencies are out of scope. -
Versions: if the repo commits an npm
package-lock.json(10 of the 26 do), the exact locked versions were checked. Otherwise the lowest version each range allows, which is the worst case. -
The headline number avoids the worst-case trap. A range like
^4.17.1may already resolve to a patched version on a fresh install. So the 69% only counts advisories whose fix is outside the declared range, where a fresh install cannot pick it up. - Date: data collected on 20 October 2026. Advisories and releases change daily, so re-running this later will give different numbers.
Finding 1: "just run npm update" doesn't work for most of it
Of the 576 advisory matches across all projects, only 204 have a fix inside the version range the project already declares. The rest need someone to edit package.json, and usually to read a changelog.
The same few packages come up again and again:
- mongoose (13 projects). Several projects are on Mongoose 4 or 5. A critical search-injection advisory is only fixed from 6.13.6 onwards, so this is a major upgrade, not a patch.
-
jsonwebtoken (8 projects). The fixes for its 2022 advisories are in 9.0.0, and most starters are on
^8.5.1or older. -
body-parser and compression (4 projects each). These are pinned with
~ranges or exact versions that stop just before the fixed release. - multer, axios, nodemailer and lodash (3 projects each). These are old majors or exact pins.
None of these are exotic packages. They are the default building blocks of an Express API, which is exactly why they end up in starters.
Finding 2: deprecated packages are easy to miss
npm prints a deprecation warning once, during install, between dozens of other lines. After that, nothing reminds you. The most common ones in this set:
-
csurf: "This package is archived and no longer maintained." -
babel-eslint: "now@babel/eslint-parser. This package will no longer receive updates." -
babel-preset-es2015: "we recommend using babel-preset-env now". -
tslint: "deprecated in favor of ESLint." -
request: "request has been deprecated", and it is still in two starters.
Half the projects carry at least one of these. Most have a direct replacement, so this is usually the cheapest kind of cleanup.
Finding 3: quiet is not the same as broken
288 dependencies (34%) had no release in two years. That is a maintenance signal, not a vulnerability. passport, for example, is in 9 of these projects and its last release is almost three years old. But "no release in years" plus "single maintainer" (29% of all dependencies here) is how packages end up deprecated a year later. It is worth knowing which of your dependencies are in that state before you build on them.
What the healthy ones have in common
The three that scored well:
-
heroku/nodejs-getting-started: 100 -
jsynowiec/node-typescript-boilerplate: 96 -
nestjs/typescript-starter: 88
They share two boring habits. They are updated regularly (all pushed within the last four months), and they commit a current lockfile, so what you clone is exactly what was tested. Small dependency lists help too, but fastify/demo scored 76 with 33 direct dependencies, so size alone isn't the problem; staleness is.
If you started from a boilerplate
-
Look at the date first. If the starter's last commit is years old, treat its
package.jsonas a list of package names, not versions. -
Run
npm audit, then read what it can't fix. The advisories that need a major upgrade are the ones that stay open. Plan them as work items, not a command. - Replace deprecated packages early. They only get harder to remove as more code depends on them.
- Commit your lockfile and check it again every few months. A dependency list ages even when your code doesn't change.
About the tool
I built deps.noticely.dev to do this check in one step. You paste a package.json (and optionally the lockfile) and get:
- the same findings as above;
- a 0–100 health score;
- an upgrade plan ordered by risk removed per hour of work.
It's free, needs no account, and stores only dependency names and versions, for 30 days. Here is a sample report, and the scoring rules are public. The code is on GitHub.
If you maintain one of the starters below and think a number is wrong, tell me in the comments and I'll correct it.
Appendix: all 26 projects
Sorted by GitHub stars. Score is the deps.noticely.dev health score (0–100). Unfixable counts high and critical advisories whose fix is outside the declared version range, so a reinstall won't pick it up. Deprecated counts dependencies their authors have deprecated.
Top comments (0)