Your package.json has 47 dependencies. When was the last time you checked if any of them were abandoned?
If you're like most developers, the answer is never. You npm install something, it works, and you move on with your life. Maybe you run npm audit once in a while when GitHub sends you that annoying Dependabot email. But that's it.
I used to be the same way. Then I got burned.
The graveyard in your node_modules
Let's talk about some famous examples.
event-stream (2018) — A popular utility package with millions of weekly downloads. The original maintainer got tired of it and handed ownership to a stranger who asked nicely. That stranger injected a targeted attack to steal cryptocurrency from Copay wallet users. The malicious code sat in the package for two months before anyone noticed.
colors and faker (2022) — The maintainer intentionally broke his own packages, pushing an update that printed an infinite loop of garbage text. He was protesting open-source exploitation. Thousands of projects broke overnight.
left-pad (2016) — One developer unpublished an 11-line package and broke the entire npm ecosystem for a few hours. React, Babel, and thousands of other packages couldn't build.
These aren't edge cases. These are warnings. And the common thread is that nobody was watching the health of these dependencies before things went sideways.
What "healthy" actually means
npm audit checks for known CVEs. That's necessary but not sufficient. A dependency can have zero reported vulnerabilities and still be a ticking time bomb.
Here's what actually matters:
Maintenance activity — When was the last commit? The last npm publish? A package that hasn't been touched in 3 years isn't "stable." It's abandoned. There's a difference between "done" (like is-number) and "dead" (like request).
Download trends — Is usage growing, flat, or declining? A declining package means the community is migrating away from it. You should probably know where they're going.
Bundle size — moment is 4.2 MB unpacked. dayjs does the same thing in 7 KB. If you're shipping a web app, this stuff adds up fast.
Known vulnerabilities — Yes, check npm audit. But also check if the vulnerabilities are actually getting patched.
Community signals — How many open issues? How many PRs sitting with no response? A repo with 200 open issues and no maintainer response in 6 months is a red flag.
How to check manually
You don't need any special tools for this. The npm registry API is public.
Check when a package was last published
npm view moment time --json | jq '.modified'
# "2022-04-07T01:25:37.007Z" <-- over 3 years ago
Check weekly downloads
curl -s https://api.npmjs.org/downloads/point/last-week/moment | jq '.downloads'
# 12847392
Still getting 12M downloads a week, but that number has been declining steadily. Legacy projects pulling it in, not new adoption.
Compare download trends
# moment vs dayjs over the last month
curl -s "https://api.npmjs.org/downloads/range/last-month/moment" | jq '.downloads[-1].downloads'
curl -s "https://api.npmjs.org/downloads/range/last-month/dayjs" | jq '.downloads[-1].downloads'
Quick vulnerability check
npm audit --json | jq '.vulnerabilities | to_entries[] | {name: .key, severity: .value.severity}'
Check package size
npm view moment dist.unpackedSize
# 4226096 (that's ~4.2 MB)
Or use bundlephobia.com for a nicer view of what actually ends up in your bundle.
The poor man's dependency audit
Here's a quick script you can run right now against any project:
#!/bin/bash
# quick-audit.sh — scan package.json for stale deps
for pkg in $(jq -r '.dependencies | keys[]' package.json); do
modified=$(npm view "$pkg" time.modified 2>/dev/null)
downloads=$(curl -s "https://api.npmjs.org/downloads/point/last-week/$pkg" | jq -r '.downloads')
echo "$pkg | last updated: $modified | weekly downloads: $downloads"
done
This takes a while because it hits the API for every package. But it works. Run it once and you'll probably be surprised by what you find.
The packages you should be worried about
Let me save you some time. If you have any of these in your package.json, it's worth investigating:
| Package | Status | What to use instead |
|---|---|---|
moment |
In maintenance mode, no new features |
dayjs or date-fns
|
request |
Deprecated since 2020 |
undici (built into Node 18+) or node-fetch
|
uuid (v3 or lower) |
Old, has known issues |
uuid@9 or crypto.randomUUID()
|
chalk (if size matters) |
Heavy for what it does |
picocolors or built-in ANSI |
lodash (full package) |
1.4 MB for a few utility functions |
lodash-es or native methods |
None of these will blow up tomorrow. But they're the kind of slow-burn risk that makes upgrades painful later.
Automating the boring stuff
The manual approach works but it's tedious. Checking 40+ dependencies one by one against the registry API is not how I want to spend my Friday afternoon.
I got tired of doing this manually, so I built a CLI called DepScope that runs the whole audit in one command:
npx depscope
DepScope — Dependency Health Report
──────────────────────────────────────────────────────
Production Dependencies (6)
A express ^4.21.0 → 4.21.0
████████████████████░░░░ 85/100 active 28,000,000/wk ↑ 209 KB ✓ secure
B lodash ^4.17.21 → 4.17.21
████████████████░░░░░░░░ 68/100 stale 51,000,000/wk → 1.4 MB ✓ secure
C moment ^2.30.1 → 2.30.1
██████████░░░░░░░░░░░░░░ 42/100 abandoned 12,500,000/wk ↓ 4.2 MB ✓ secure
↳ Consider: dayjs — 2KB, same API, actively maintained
F event-stream ^4.0.1 → 4.0.1
██░░░░░░░░░░░░░░░░░░░░░░ 8/100 abandoned 320,000/wk ↓ 45 KB ✗ 1 vuln (critical)
──────────────────────────────────────────────────────
Project Health: B ████████████████░░░░░░░░ 64/100
⚠ 2 abandoned packages
⚠ 1 package with known vulnerabilities
It scores each dependency across maintenance, popularity, size, security, and trend — then gives you a letter grade. Pipe --json to get machine-readable output for CI. Use --fix to get suggested replacements.
But honestly, whether you use DepScope or the bash script above or something else entirely — the point is the same: check your dependencies. Not just when things break. Regularly.
What to do right now
- Run
npm auditon your biggest project. Read the output instead of ignoring it. - Pick your three least-familiar dependencies and check when they were last published.
- If anything hasn't been updated in 2+ years, look for alternatives.
- Add a dependency check to your CI pipeline. Even a simple
npm audit --audit-level=highis better than nothing.
Your package.json is a list of promises from strangers on the internet. Trust, but verify.
If you found this useful, I write about dependency hygiene, dev tools, and building stuff at @WSDevGuy on Twitter.
Top comments (0)