Pick the maintenance signal you can get in one second: days since the last release.
I pulled it from the npm registry for 18 ESLint plugins on 2026-08-12. The three with the deepest install base are the three that have gone quietest.
| plugin | days since release | releases in 12mo |
|---|---|---|
| eslint-plugin-jsx-a11y | 655 | 0 |
| eslint-plugin-react | 495 | 0 |
| eslint-plugin-import | 417 | 0 |
| eslint-plugin-promise | 107 | 1 |
| eslint-plugin-security | 61 | 2 |
| eslint-plugin-sonarjs | 28 | 9 |
| eslint-plugin-unicorn | 8 | 17 |
| eslint-plugin-n | 3 | 12 |
| eslint-plugin-jest | 0 | 35 |
Nine of the eighteen I measured shipped nothing at all in the last twelve months. Nearly two years of silence on the plugin that half the accessibility tooling in React depends on.
Dormant is not dead
Before drawing the obvious conclusion, the honest caveat: a plugin that stops releasing may simply be finished. jsx-a11y encodes WAI-ARIA rules. ARIA does not change every quarter. A stable spec produces a stable plugin, and "no releases" is the correct output for a package with nothing left to do.
So days-since-release is a prompt, not a verdict. Three signals actually separate finished from abandoned, and all three are free:
1. The npm deprecation flag. eslint-plugin-standard carries one. That is the maintainer telling you directly, and it is machine-readable — no interpretation required.
2. Supersession. eslint-plugin-node last shipped 2,328 days ago — over six years — because it was replaced by eslint-plugin-n, which shipped 3 days ago. One of those numbers is alarming and the other explains it. A rename is invisible to anyone reading only the old package's page.
3. Whether it still works on your ESLint. This is the one that matters and the one nobody checks until it breaks. A plugin frozen before flat config became the default is not "stable," it is on a countdown.
The genuinely dead tier
Sorted by silence, these are the ones where no reading rescues the number:
eslint-plugin-scanjs-rules 3,296 days (9 years)
eslint-plugin-node 2,328 days superseded by eslint-plugin-n
eslint-plugin-standard 2,088 days npm-deprecated
eslint-plugin-flowtype 1,748 days Flow itself receded
eslint-plugin-xss 1,507 days
eslint-plugin-security-node 951 days
Every one of these still installs cleanly today. npm will not warn you, your lockfile will not warn you, and a config that references them keeps passing — because a plugin whose rules never fire looks exactly like a codebase with no problems. That is the same failure shape as a CI check that was disabled rather than failing: silence reads as success.
The one that came back
eslint-plugin-security is the interesting row. It went 3.0.1 in June 2024 → nothing for 20 months → 4.0.0 in February 2026, and shipped again in June. If you had measured it in January you would have called it abandoned, correctly, and been wrong by March.
That is why a claim needs an expiry date rather than a verdict. "Unmaintained" is not a property of a package. It is a measurement with a date on it, and this one moved.
Measure your own config
Do not use time.modified for this. It is the obvious field and it is the wrong one: npm bumps it on any metadata change, so deprecating a package or transferring ownership makes a dead package look freshly touched. eslint-plugin-flowtype reports time.modified of 2026-01-24 — seven months ago, apparently maintained. Its last actual release was 2021-10-29. That is the 1,748-day row above, and the gap between the two fields is 1,548 days of false reassurance.
Read the publish date of the current version instead:
npm view <plugin> version # e.g. 8.0.3
npm view <plugin> time.8.0.3 # the date that version shipped
Or resolve the whole set at once:
node -e "for (const p of Object.keys(require('./package.json').devDependencies ?? {})) \
fetch('https://registry.npmjs.org/'+p).then(r=>r.json()) \
.then(j => console.log(p, j.time[j['dist-tags'].latest].slice(0,10)))"
Then apply the three checks above to anything past a year. Most will be fine. The point is knowing which ones you are betting on — eslint-plugin-import at 417 days is a dependency worth having an opinion about, given what it does on every lint run.
All figures resolved from the npm registry on 2026-08-12 and already drifting — eslint-plugin-jest was at 0 days when I measured it. Re-run the one-liner rather than citing mine.
Source at github.com/ofri-peretz/eslint · packages at npmjs.com/~ofriperetz · more at dev.to/ofri-peretz.
What's the oldest plugin in your lockfile — and did you know it before you looked?
Top comments (3)
The "dormant is not dead" caveat is doing a lot of honest work here -- jsx-a11y going quiet is the correct output for a stable spec, and treating days-since-release as a prompt rather than a verdict is the right frame. The supersession signal (eslint-plugin-node -> eslint-plugin-n) is probably the strongest of the three, since it's a maintainer-visible pointer rather than an inference.
One more free signal I've leaned on: issue triage latency. A plugin with open issues getting maintainer responses is alive even with zero releases; a plugin where the last maintainer comment predates the last release by a year is a different story than the registry alone tells. Did the deprecation-flag check cover the case where a plugin is superseded but the old package never got flagged? I've seen that gap swallow real migrations.
Days-since-last-release is underrated as a one-second signal because it's the only maintenance metric that can't be gamed by the project itself - stars are history, download counts are momentum, but a quiet release log is a fact about right now. The three-quietest-have-the-deepest-install-base finding is the real story: install base is a lagging indicator of PAST quality, and the gap between it and current maintenance is exactly where supply-chain risk accumulates. Everyone's dependency tree has a few of these - packages that won the popularity contest in 2021 and have been coasting since, still getting installed fifty thousand times a day on reputation alone. The companion metric I'd pair it with: open-issue response time. A quiet release log with an active maintainer triaging issues is hibernation; quiet on both is abandonment wearing a popular package's name.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.