As of July 31, 2025 there are... let's see...
npm i all-the-package-names
node -e 'console.log(require("all-the-package-names").length)'
3532585
3,532,585 packages published in the npmjs registry. This includes the all-the-package-names
package and its four dependencies, is-number
, tap-spec
, tape
and all-the-package-repos
.
Does that seem a little ridiculous that such a simple library, a list of all npm packages, has four dependencies? The answer to this rhetorical question becomes far more clear when you consider the dependencies of those dependencies.
npm i --include=dev # 3 "critical vulnerabilities" detected btw
ls node_modules
all-the-package-repos es-define-property is-arguments minimist side-channel-list
ansi-regex es-errors isarray mock-property side-channel-map
ansi-styles es-get-iterator is-array-buffer object-assign side-channel-weakmap
array-buffer-byte-length es-object-atoms is-async-function object.assign split
arraybuffer.prototype.slice es-set-tostringtag is-bigint object-inspect stop-iteration-iterator
array.prototype.every es-to-primitive is-boolean-object object-is string_decoder
async-function figures is-callable object-keys string.prototype.trim
available-typed-arrays for-each is-core-module once string.prototype.trimend
balanced-match fs.realpath is-data-view own-keys string.prototype.trimstart
brace-expansion function-bind is-date-object parse-ms strip-ansi
buffer-shims function.prototype.name is-finalizationregistry path-is-absolute supports-color
call-bind functions-have-names is-finite path-parse supports-preserve-symlinks-flag
call-bind-apply-helpers get-intrinsic is-generator-function plur tape
call-bound get-package-type is-map possible-typed-array-names tap-out
chalk get-proto is-negative-zero pretty-ms tap-spec
concat-map get-symbol-description is-number process-nextick-args through
core-util-is glob is-number-object readable-stream through2
count-array-values globalthis is-regex re-emitter trim
data-view-buffer gopd is-set reflect.getprototypeof typed-array-buffer
data-view-byte-length has-ansi is-shared-array-buffer regexp.prototype.flags typed-array-byte-length
data-view-byte-offset has-bigints is-string repeat-string typed-array-byte-offset
deep-equal has-dynamic-import is-symbol resolve typed-array-length
defined hasown is-typed-array safe-array-concat unbox-primitive
define-data-property has-property-descriptors is-weakmap safe-buffer util-deprecate
define-properties has-proto is-weakref safe-push-apply which-boxed-primitive
dotignore has-symbols is-weakset safe-regex-test which-builtin-type
dunder-proto has-tostringtag @ljharb set-function-length which-collection
duplexer inflight lodash set-function-name which-typed-array
es-abstract inherits math-intrinsics set-proto wrappy
escape-string-regexp internal-slot minimatch side-channel xtend
Wtf! That's one-hundred-and-fifty packages!2 To be fair, these are developer dependencies which are only required for contributors to develop, build and release the all-the-package-names
package; regardless, this is clearly an issue.
These packages are authored by 19 unique developers (in addition to 5 unattributed packages). Do you really trust the author of the isarray
package not to run malicious code on your computer? How about the author of the escape-string-regex
package? Do you trust them not to sell the package to a malicious actor, or to get phished?
The answer to these questions for the vast majority of JavaScript developers should be no; not because the authors of the aforementioned packages are necessarily malicious (they are likely not), but because you simply don't know how trustworthy these packages are until you investigate. And let's be honest... you're not investigating.
In the beginning there was UNIX. Any program that wasn't included with the operating system would have to be installed by downloading and extracting an archive, then running a ./configure
script and finally make
. This got annoying real fast.
Then came DPKG, likely the oldest package manager still in use today. When it was released by The Debian Project in 1993, DPKG had no ability to deal with dependency resolution or remote repositories. These shortcomings would later be addressed with the release of APT in 1998. Today when we think of a package manager, we think of something like APT, which can resolve and fetch dependencies from a remote repository.
While DPKG and other package managers for operating system were being developed, the first large scale ecosystem-specific code repositories started coming online, notably CTAN for TeX and later CPAN for Perl (both are still in use today).
CPAN is really the first thing that resembles npm. It has one community-open unified repository (for the most part) and a command line utility for searching, downloading and publishing packages.
An early attempt at creating a package manager for JavaScript was JSAN, of course, based on CPAN. JSAN was released four years before NodeJS and the advent of JavaScript for the backend, which is possibly why it never picked up any real steam.
This finally brings us around to npm, which was released in January 2010 to serve as the package manager and registry for the newly released NodeJS.
When Isaac Schlueter pushed the first commit to the npm git repository, there was no registry as we know it today. Packages came from a JSON file in this git repo, which has sadly been lost to time.
This system was quickly replaced with a CouchDB app. At the time, anyone could publish to the registry without authentication and override anyone else's packages. The current iteration of the npm registry is a more secure and distributed version of this original CouchDB system.
Contrary to the answer provided by the little AI box when you type "what was the first npm package?" into Google, the first package published was actually abbrev, not npm itself.1
Due to changes to the npm registry over the last decade-and-a-half, it's hard to get exact data on the historical package count. These numbers are rough estimates and have been compiled from various blog posts, tweets and git commits.
The npm registry is really big3,4. This makes some sense, being that JavaScript is, much to my chagrin, the most used programming language.
It's tempting to scoff at this number and conclude that package count alone is indicative of something bad. First, let's put it into perspective against some other popular software registries:
We can clearly see that npm is more or less on par with these other registries in terms of raw package count, even being completely eclipsed by Maven Central. So why does npm have such a terrible security reputation? Let's look at transitive dependencies.
These are the median number of transitive dependencies for a few popular registries, calculated by GitHub in 2020:5
GitHub didn't have any data for transitive Java dependencies in the Maven Central repository, so I wrote a script to analyze 10,000 random packages (in 2025):
This is our first glaring issue.
Ultimately, this comes down to two things: the standard library and developer culture.
Compared to languages like Java or Go, Node has a tiny standard library. In the last decade or so, we've seen massive improvement on this first problem with the addition of native FS, buffers, async hooks, fetch, etc. However, we are left over with the rot of obsolete packages like lodash, node-fetch, request, bluebird, and moment, which were previously very useful.
The main problem though, is micropackaging, a philosophy that has completely taken over the JavaScript ecosystem. Thousands of packages on the registry, each with millions of downloads per week consist solely of one liner functions. Rather than writing a quick utility function, JavaScript developers prefer to include a third party package.
Additionally, thousands of spam packages can be attributed to perverse incentives from the Tea protocol and web developers attempting to pad their digital resume with claims of maintaining several popular packages.
The supply chain threat is not just theoretical; it's absolutely epidemic to the JavaScript ecosystem. Personally, I opt to do any NodeJS development in a virtual machine.
There are countless examples of hacked package maintainers, packages being sold to malicious actors, and even malware being placed by the legitimate author. Everything from "protestware" to crypto miners to multi platform RATs are sneaking into your machine via npm install
. The smart malware will even steal your registry token from .npmrc
to infect your packages.
Let's take a look at some famous examples.
In July of 2025, a clever hacker noticed that npmjs.org had no SPF record configured. They proceeded to take advantage of this with a phishing campaign targeting maintainers of some popular packages. The packages eslint-config-prettier
, eslint-plugin-prettier
, synckit
, @pkgr/core
, napi-postinstall
, got-fetch
, and is
, with a collective weekly download count of 96,063,394 were promptly compromised with malware targeting Windows.8
One particularly infuriating case is the Peacenotwar "protestware." This malware was planted by the real maintainer of the node-ipc
package, and it's goal was to wipe the computers of anyone with an IP address in Belarus or Russia. A good reminder that people are not their governments, and that IP geolocation is not accurate. Also, believe it or not, this guy faced zero consequences and is still the maintainer of node-ipc
and various other packages.7
The npm supply chain tactic also seems to be a favorite among hackers linked to the DPRK.9 In 2023, the Lazarus APT compromised connect-kit
, a package used for connecting JavaScript dApps to Ledger cryptocurrency hardware wallets. Despite the malicious code only being live for 5 hours, they managed to swipe over $600,000 worth of cryptocurrency from unsuspecting users.10
There are so... so many more examples of compromised npm packages. I invite you to just google "npm supply chain" and see how many results pop up.
The registry has already implemented mandatory MFA for package maintainers, but that's not cutting it. I suggest that npm implements the following changes:
And perhaps more importantly, developers need to stop being lazy. You don't need a package to check if a number is even!
It's past time to stop carelessly running npm install
.