Skip to content

feat: decentralized registries and mirrors#2386

Draft
Aslemammad wants to merge 1 commit intonpmx-dev:mainfrom
Aslemammad:feat/registry-proxy-sumdb
Draft

feat: decentralized registries and mirrors#2386
Aslemammad wants to merge 1 commit intonpmx-dev:mainfrom
Aslemammad:feat/registry-proxy-sumdb

Conversation

@Aslemammad
Copy link
Copy Markdown

@Aslemammad Aslemammad commented Apr 5, 2026

WORK IN PROGRESS: I AM STILL SHAPING THIS DESCRIPTION AND ANSWERING SOME OF THESE QUESTIONS TO CLARIFY THE IDEA.

This is a pull request for my two months of research on how we can decentralize npm by not breaking any mainstream behavior, so we make it as easy as possible to adopt new paradigms by users without having to deal with new conventions or at least a inconvenient number of them.

“I have only made this letter longer because I have not had the time to make it shorter.”

I'd avoid making this pull request description shorter, not because of time, but because i cannot hold my excitement any more than that. So forgive me for the obvious writing mistakes.

I went through a journey of ideas. Initially I visualized this as a localhost server called denpm that would store its local url in ~/.npmrc as registry=http://denpm.local and then from there it'd distribute the pacakge requests, mapping each package to a random registry, something like npm add vite would go through denpm.local -> registry.npmjs.org, denpm.local -> registry.yarnpkg.com, denpm.local -> registry.npmmirror.co, denpm.local -> r.cnpmjs.org or perhaps any other registry the user might want to provide.

This is totally possible due to the nature of redirects in npm. So npm add vite --registry=http://denpm.local would result into this package-lock.json if the localhost server decides to just redirect the request to registry.npmjs.org.

    "node_modules/vite": {
      "version": "8.0.1",
      "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.1.tgz",
      "integrity": "sha512-wt+Z2qIhfFt85uiyRt5LPU4oVEJBXj8hZNWKeqFG4gRG/0RaRGJ7njQCwzFVjO+v4+Ipmf5CY7VdmZRAYYBPHw==",
    }  

Before the redirect, the source, or the proxy server, which is in this case denpm.local can do a whole lot of stuff. It can check the signatures behind the package to make sure it hasn't been tampered or the destination server, the registry, the mirror, which is in this case registry.npmjs.org, does not serve the user something different than what it previously claimed through the signature.

Or to stimulate decentralization, the proxy can just randomly assign each package to a distinct registry. This would potentially remove the single point of failure nature of npm and our overreliance on it.

I'm bringing all of this just to mention that the possibility of opting out of the npm registry is there and unbelievably it's as simple as npm config set registry http://denpm.local/.

We all love npm and it's the giant everyone is standing on its shoulder, BUT if there's an opportunity to ease the work for the npm servers, distribute the load being lifted, increase security and a whole lot of other stuff, then why not explore those wins?

The recent growth over npmx showed that all of this is possible as long as we make something smoother than what's available.

The thing that striked me after researching denpm was that the golang ecosystem had nearly solved the package management issue through a mix of centralization and a lot of decentralization. So that led me to dig even more into how they did it and how they leveraged transparency logs to allow proxies act in an authentic manner. At that point I realized a new CLI is not only not enough, but it might be unncessary.

So the biggest inspiration for this effort is the golang ecosystem. Centralization at that point would be part of npmx itselsf, specifically the Checksum database it'd maintain. Decentralization would be basically everything else, like the npm registry and other registries and mirrors.

I keep separating registries and mirrors, though might there be a slight technical difference, but both should be advertised and users should know the difference between them and the fact that spinning up a new registry is way cheaper than spinning a full mirror.

The community might decide to maintain servers that are one-to-one replications of the npm registry itself or at least, or a portion of it. That's what I'd call a mirror, like registry.npmmirror.co by cnpm.

Registries are though more important, they might want to host exclusive packages. For instance, registry.viteplus.dev would decide to only host packages like vite or vitest only, or even better, their supply chain.

So registries for ownership and mirrors for distribution and obviously, mirroring. Imagine a world where each maintainer can host their own packages under their own domain if they prefer, which is totally possible, but hasn't been mainstream yet due to friction I'd argue.

That's where VSR or Verdaccio can join the effort as well to ease up the hosting side.

Back to the solution, in the next few sections I'll go in details around how the puzzle pieces are going to fit together.

Checksum Database

Something like sum.npmx.dev.

This is the point of centralization in the puzzle. It'd solve the problem of package unpublishes, mutability and version replacements in the new decentralized package management world. Two mirrors won't be able to ship different bytes for the same version of the same package, if one acts unfaithfully, it'd be easily caught by what's already recorded in the checksum database.

The initial and main consumer of this checksum database would be the npmx proxy, but after gaining momentum, it might be something that the package managers might want to rely on, independantly.

Merkle Trees and Transparency Logs

More details in Russ Cox's blog post. Briefly, this data structure would allow us to create a tamper-evident database so a released package would be cryptographically frozen and therefore cannot be tampered.

And similar to the golang checksum database, we'd expose APIs that'd allow any user or service to verify the merkle tree we're hosting.

The checksum database itself allows for the auditability of registries and proxies. This data structure would allow the auditability for the checksum database itself.
So it's not an unverifiable point of centralization but rather a totally verifiable and consistent one.

Proxy

registry.npmx.dev or proxy.npmx.dev. This the same url that the user would have to pass to npm config set registry.

It'd handle the job of redirects to the right registries, making sure that they serve the right content, returning consistent manifests and all the security improvments we can make over npm.

In the current mvp, the proxy only allows project with the integrity field to be stored in the checksum database and returned to the user to increase the security.
So packages with no integrity (not signed by the registry) are not allowed to be stored. This can be changed but it also means less security, even though we sign the each field in the checksum database too.

/-/npm/v1/keys

This what npm audit signatures use to audit the signatures of the packages and verify that we're consuming what the registry has actually signed.

``:

{
  "keys": [
    {
      "expires": "2025-01-29T00:00:00.000Z",
      "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA",
      "keytype": "ecdsa-sha2-nistp256",
      "scheme": "ecdsa-sha2-nistp256",
      "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+IhuteBJbuHcA5UogKo0EWtlWwW6KSaKoTNEYL7JlCQiVnkhBktUgg=="
    },
    {
      "expires": null,
      "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U",
      "keytype": "ecdsa-sha2-nistp256",
      "scheme": "ecdsa-sha2-nistp256",
      "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEY6Ya7W++7aUPzvMTrezH6Ycx3c+HOKYCcNGybJZSCJq/fd7Qa8uuAKtdIkUQtQiEKERhAmE5lMMJhP8OkDOa2g=="
    }
  ]
}  

registry.npmx.dev/-/npm/v1/keys not only can host those keys by the npm registry, but all the keys from all other registries and mirrrors.

I assume this file won't be hundreds of megabytes or even more, but if my assumption is wrong, we can cherry pick the keys we return to the user based on what registries they prefer in a potential dashboard using the authorization http header.

GET /-/npm/v1/keys HTTP/1.1
Host: registry.npmjs.org
user-agent: npm/10.2.4 node/v20.11.0 linux x64 workspaces/false
npm-session: b9c1d2e3f4a5b6c7        ← new random ID, new invocation
npm-command: audit
authorization: Bearer npm_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
accept-encoding: gzip, deflate, br
accept: */*
connection: keep-alive
if-none-match: "abc123etag"  

The New world

By avoiding overdependence on the npm registry, new kind of registries and mirrors would emerge. One I keep dreaming of that'd mitigate most of attacks happening on npm, remind you that most attacks happen on npm LINK ARTICLE, is a mirror.socket.dev which would only host what's available on npm once it goes their in-house audits, which are pretty good. They have been able to catch most of the recent attacks on npm before anyone else, but still, since there's no way to affect user workflows directly, like through explicit errors and failures in npm add by avoiding to serve a particular package, a lot of potential is being missed.

Another kind of registries I imagine are organization backed registries that host only what they ship or what they rely on, like the registry.viteplus.dev example mentioned above. That'd be the same story with maintainer backed registries, like registry.roe.dev hosting packages that Daniel maintains.

FAQ

I am adding these as prompts for myself. If the PR is going to persuade anyone, it should answer these directly instead of assuming the reader will fill the gaps for me.

Open FAQ prompts

What exact npm failure modes am I trying to solve first?

Which important npm security problems am I explicitly not solving in this PR?

What is the concrete win for users if they adopt this?

Why a proxy instead of a new CLI?

Why a sumdb instead of relying only on lockfile integrity?

Why keep lockfiles pointing at the upstream tarball URL instead of the proxy URL?

What is the trust root in this system?

What exactly does keyId mean here?

What does a successful verification prove?

What does it not prove?

What does “decentralization” mean in this proposal?

What is decentralized today and what is still centralized?

If the proxy currently fetches from the first configured registry, how should readers interpret that limitation?

Are mirrors and registries different in principle, or just in operational practice?

Are package names still the global npm names?

If two sources claim the same package and version but offer different tarballs, what happens?

Does this stop malicious maintainers?

Does this stop preinstall and postinstall malware?

Does this stop unpublishing or version replacement?

What does this system say about content authenticity versus content safety?

Who runs the sumdb?

Which npm client flows already work with this prototype?

Which npm flows are intentionally unsupported right now?

Why is this better than a plain mirror?

Is the long-term goal to decentralize hosting, trust, naming, or all three?

What is prototype-only in this PR?

What is already real and verified?

What would have to change next to support real multi-registry fetch selection?

What is the minimal next milestone that would prove this idea is viable?

“This is still centralized.” What is my answer?

“This doesn’t solve install-time code execution.” What is my answer?

“This just re-wraps npm trust.” What is my answer?

“Why not just use npm mirrors?” What is my answer?

“Why should anyone trust sum.npmx.dev?” What is my answer?

“If the proxy isn’t in the lockfile, what value is it adding?” What is my answer?

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs.npmx.dev Ready Ready Preview, Comment Apr 5, 2026 4:49am
npmx.dev Ready Ready Preview, Comment Apr 5, 2026 4:49am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
npmx-lunaria Ignored Ignored Apr 5, 2026 4:49am

Request Review

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 5, 2026

Hello! Thank you for opening your first PR to npmx, @Aslemammad! 🚀

Here’s what will happen next:

  1. Our GitHub bots will run to check your changes.
    If they spot any issues you will see some error messages on this PR.
    Don’t hesitate to ask any questions if you’re not sure what these mean!

  2. In a few minutes, you’ll be able to see a preview of your changes on Vercel

  3. One or more of our maintainers will take a look and may ask you to make changes.
    We try to be responsive, but don’t worry if this takes a few days.

@Aslemammad Aslemammad changed the title feat: package management through decentralized registries and centralized proxies feat: decentralized registries and proxies Apr 5, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 5, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@Aslemammad Aslemammad changed the title feat: decentralized registries and proxies feat: decentralized registries and mirrors Apr 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant