The Package Name Land Grab Is Real, and It's Getting Worse
You've Got a Great Name. Someone Else Got There First.
"I've got it. The perfect name."
You type it into pip. Or npm. And there it is: a repo from 2014. Three commits. No README. Last touched when Obama was still president. But the name? Taken.
This is happening to developers every day. Python's user base exploded. JavaScript's ecosystem grew into something nobody planned for. And the central registries that hold it all together, PyPI and npm, are running out of good names. Not just any names. The short, clean, memorable ones that every developer reaches for: json, request, api, test.
Think of them as the Ginza or Manhattan of the digital world. Prime real estate. And it's basically all gone.
This isn't just annoying. It's turning into a real governance problem, one that touches on digital land rights, trust, security, and how we organize shared resources. Let me explain what happened.
How Did We Get Here?
Micro-packages Ate the Namespace
Part of the blame falls on a culture that took a good idea too far. Especially in the npm world.
"Do one thing and do it well." Great principle. Unix got it right. But npm developers ran with it to an absurd extreme. Building a car? Sure, package the tires and the steering wheel separately. But also the bolts. The washers. The paint pigment. Each one gets its own globally unique name.
The poster child here is is-odd. A package that checks if a number is odd. The actual logic? return n % 2 === 1;. That's it. A few lines. And it gets downloaded tens of millions of times a week. Oh, and it depends on is-number. A package to check if something is a number. You can't make this up.
The DRY principle ("Don't Repeat Yourself") was the justification. Fair enough. But nobody stopped to think about what it costs to burn a globally unique name on a one-liner. Stuff that should've stayed as a helper function in your codebase got registered in a shared global registry instead. One by one, the good names disappeared.
Typosquatting Made It Worse
Then there's the security angle. Bad actors register names like requesst or py-requests, banking on someone's typo to slip malware into a build. Registry maintainers have to block these lookalikes preemptively. That means even more names get locked up as buffer zones, squeezing the pool of available names even further.
Why Not Just Reclaim Abandoned Names?
Seems obvious, right? If a package hasn't been touched in a decade, free up the name and let someone else use it. Except people tried that. It went badly.
The event-stream Disaster
In 2018, someone offered to take over maintenance of event-stream, a popular but neglected npm package. The original author handed it off. The new maintainer then quietly injected malware that targeted a specific Bitcoin wallet. Millions of downloads, all trusting the package because of its track record.
When you inherit a name, you inherit the trust attached to it. That trust becomes a weapon.
The left-pad Meltdown
March 2016. A developer named Azer Koçulu got into a fight with npm over a package name ("kik," which a messaging company wanted). npm sided with the company. Koçulu, furious, yanked all 270-something of his packages off the registry.
One of them was left-pad. Eleven lines of code. Pads the left side of a string. Trivial, right? Except Babel depended on it. React depended on it. Node.js depended on it. Builds broke everywhere. The JavaScript ecosystem ground to a halt over eleven lines.
The takeaway was brutal: even a tiny, ancient, seemingly insignificant package might be holding up critical infrastructure somewhere. You can't just delete things.
npm now restricts package deletion because of this. Once it's published, it stays.
Who Decides "Abandoned"?
There's a more basic problem too. How do you tell the difference between a project that's abandoned and one that's just... done? A library that does its job and doesn't need updates? You'd have to contact the owner, review the code, check downstream dependencies. For millions of packages. On a volunteer basis. That's not happening. So names stay locked up, basically forever. Retired jersey numbers.
Three Ecosystems, Three Philosophies
The major language communities have taken very different approaches to this mess.
Python and JavaScript: Tightening the Rules
PyPI and npm started out as open markets. Publish whatever you want, name it whatever you want. Freedom. That era's over. Both registries now require two-factor auth. Python has PEP 541, a formal process for reclaiming names from dead projects. npm has similar policies.
The free frontier turned into a city with zoning laws.
What's PEP 541? A 2017 Python Enhancement Proposal that spells out how to handle name disputes on PyPI. It covers abandoned projects, trademark claims, and name squatting. Basically, it's the rulebook for who gets to keep a name.
Go: Skip the Registry Entirely
Go did something different. No central registry at all. Your import path is just a URL: github.com/someone/something. The domain name is the namespace. Problem solved?
Not quite. Repos get deleted. Accounts get nuked. Your build breaks because someone's GitHub disappeared. So Google built a proxy (proxy.golang.org) that caches everything centrally. They ended up with a hybrid: names are decentralized, but the data is backed up in one place.
Zooko's Triangle says you can pick two out of three: human-readable names, globally unique names, or decentralized names. You can't have all three. Go tried to get around it. They got two and a half.
Rust: Once Published, Published Forever
Rust came late enough to learn from everyone else's mistakes. Cargo's rule is simple: you can't delete a published package. Period. They also chose not to add user scopes (@user/package). The whole namespace is shared, like a public park, and it's managed accordingly.
The thinking: if one person walks away from a project, the community can keep it alive. Your bus factor goes up. "Digital urban planning," essentially.
The Tragedy of the Commons, Software Edition
Here's the pattern: a shared resource (the namespace) is open to everyone, so individuals grab names "just in case," and the collective suffers. Classic commons problem.
What's weird is how differently we treat package names versus domain names. Domain names are private property. People buy and sell them openly. A good .com can fetch six or seven figures. But try selling a PyPI package name and the community will eat you alive.
There's a deep-seated belief in open source that names belong to everyone. They're commons, not assets. Selling one feels like a betrayal. So the "if you don't need it, sell it" pressure valve that works for domains doesn't exist here. Names just sit there. Unused. Unreleased. Stuck.
And yet we keep chasing flat, unscoped names when @user/package exists as a solution. Why? Because requests feels like a brand. @some-person/requests doesn't. We want the prime real estate, not a unit in a subdivision.
What Comes Next?
Name scarcity is only going to get worse. But a couple of ideas are floating around.
One is AI-driven resolution. Maybe humans don't need to remember package names at all. You describe what you need, and an AI pulls the right package by hash or by function signature. Names become metadata, not identifiers.
Another is reputation-based allocation. Instead of first-come-first-served, names could flow toward maintainers with track records. Trust scores, contribution history, community endorsement. Something more fluid.
Both of these are speculative. For now, we're stuck with the system we've got: a flat namespace that's mostly full, governed by rules that were written after things broke.
Next time you come up with the perfect package name, check the registry first. Odds are, someone beat you to it in 2013. Their repo has one file in it. And there's nothing you can do about it.
Maybe that's fine. Maybe the era of human-readable names as the primary interface is ending anyway. The next "great name" you come up with might not be for a human reader. It might be a prompt.
I'm not sure how I feel about that yet.
Top comments (0)