[{"data":1,"prerenderedAt":355},["ShallowReactive",2],{"NoscriptNav_XrRK2e2e8meJ0jKVGkb5ULGQDVi3UiFQ9nupAr7Yns":3,"\u002Fideas\u002Ffeatures-everyone-should-steal-from-npmx":8},["Island",4],{"key":5,"result":6},"NoscriptNav_XrRK2e2e8meJ0jKVGkb5ULGQDVi3UiFQ9nupAr7Yns",{"head":7},{},{"id":9,"title":10,"authors":11,"body":13,"canonicalUrl":341,"canonicalWebsiteName":342,"category":343,"date":344,"description":345,"extension":346,"featured":347,"fullWidthLayout":347,"image":348,"imageAlt":348,"location":348,"meta":349,"metaImage":348,"navigation":350,"path":351,"seo":352,"stem":353,"venue":348,"venueUrl":348,"__hash__":354},"ideas\u002Fideas\u002Ffeatures-everyone-should-steal-from-npmx.md","Features everyone should steal from npmx",[12],"andrew",{"type":14,"value":15,"toc":337},"minimark",[16,42,51,325,328],[17,18,19,20,27,28,33,34,37,38,41],"p",{},"For most of the time GitHub has owned npm, the public-facing website at npmjs.com has been effectively frozen, with the issue tracker accumulating years of requests that nobody on the inside seemed to be reading. In January ",[21,22,26],"a",{"href":23,"rel":24},"https:\u002F\u002Froe.dev",[25],"nofollow","Daniel Roe"," started ",[21,29,32],{"href":30,"rel":31},"https:\u002F\u002Fnpmx.dev",[25],"npmx.dev"," as an alternative web frontend over the same registry data, posted about it on Bluesky, and within a fortnight years of pent-up demand had turned into a thousand issues and pull requests on a repo that would actually merge them, with the contributor count passing a hundred a couple of days after that. It helps that every npmjs.com URL works with the hostname swapped to ",[35,36,32],"code",{}," or ",[35,39,40],{},"xnpmjs.com",", the same trick Invidious and Nitter used, so browser extensions and muscle memory carry straight over. The competitive pressure appears to have worked: npmjs.com shipped dark mode last month, the single most upvoted feature request on the tracker for something like five years, and there are signs of other long-dormant tickets being picked up.",[17,43,44,45,50],{},"Whether or not that continues, npmx has turned into a useful catalogue of ideas for anyone building a package registry website, and the ",[21,46,49],{"href":47,"rel":48},"https:\u002F\u002Fgithub.com\u002Fnpmx-dev\u002Fnpmx.dev",[25],"whole thing is MIT licensed"," where the npm registry and website remain closed source, so every feature below comes with a working reference implementation rather than just screenshots. Prior art from other ecosystems is noted where it exists.",[52,53,54,74,96,114,124,136,146,162,174,186,202,208,220,230,248,267,273,285,309,319],"ul",{},[55,56,57,61,62,67,68,73],"li",{},[58,59,60],"strong",{},"Transitive install size."," The number shown is the unpacked size of the package plus every dependency it pulls in, which is what actually lands on disk, rather than the single tarball size that crates.io and PyPI show. JavaScript developers have been getting this from ",[21,63,66],{"href":64,"rel":65},"https:\u002F\u002Fbundlephobia.com",[25],"bundlephobia"," and ",[21,69,72],{"href":70,"rel":71},"https:\u002F\u002Fpackagephobia.com",[25],"packagephobia"," for years.",[55,75,76,79,80,83,84,87,88,91,92,95],{},[58,77,78],{},"Install script disclosure."," Any ",[35,81,82],{},"preinstall",", ",[35,85,86],{},"install",", or ",[35,89,90],{},"postinstall"," script in the manifest is rendered on the package page along with the ",[35,93,94],{},"npx"," packages those scripts would fetch, with links into the code browser so you can read what runs. Worth having in front of you given how many supply-chain incidents start with a postinstall hook.",[55,97,98,101,102,107,108,113],{},[58,99,100],{},"Outdated and vulnerable dependency trees."," Rather than a flat list of declared dependencies, you get an expandable tree where each node is annotated with how far behind latest it is and whether it appears in ",[21,103,106],{"href":104,"rel":105},"https:\u002F\u002Fosv.dev",[25],"OSV",", recursively through transitives. Google's ",[21,109,112],{"href":110,"rel":111},"https:\u002F\u002Fdeps.dev",[25],"deps.dev"," does something similar across ecosystems.",[55,115,116,119,120,123],{},[58,117,118],{},"Version range resolution."," Wherever a semver range like ",[35,121,122],{},"^1.0.0"," appears it is shown alongside the concrete version it currently resolves to, which saves a round trip to the CLI when you are trying to work out what you would actually get.",[55,125,126,129,130,135],{},[58,127,128],{},"Module replacement suggestions."," Packages that appear in the ",[21,131,134],{"href":132,"rel":133},"https:\u002F\u002Fgithub.com\u002Fes-tooling\u002Fmodule-replacements",[25],"e18e module-replacements dataset"," get a banner pointing at the native API or lighter alternative, with MDN links for the native cases.",[55,137,138,141,142,145],{},[58,139,140],{},"Module format and types badges."," ESM, CJS, or dual is shown next to the package name, as is whether TypeScript types are bundled or need a separate ",[35,143,144],{},"@types\u002F*"," install, plus the declared Node engine range. JavaScript-specific in the details but the general idea of \"will this work with my toolchain\" badges travels; crates.io's MSRV field and edition badge are in the same spirit.",[55,147,148,151,152,157,158,161],{},[58,149,150],{},"Multi-forge repository stats."," Star and fork counts are fetched from ",[21,153,156],{"href":154,"rel":155},"https:\u002F\u002Fdocs.npmx.dev\u002Fguide\u002Ffeatures#supported-git-providers",[25],"GitHub, GitLab, Bitbucket, Codeberg, Gitee, Sourcehut, Forgejo, Gitea, Radicle, and Tangled",", depending on where the ",[35,159,160],{},"repository"," field points, rather than special-casing GitHub.",[55,163,164,167,168,173],{},[58,165,166],{},"Cross-registry availability."," Scoped packages that also exist on ",[21,169,172],{"href":170,"rel":171},"https:\u002F\u002Fjsr.io",[25],"JSR"," are flagged as such. The npm\u002FJSR pairing is particular to JavaScript but \"this is also on registry X\" applies anywhere ecosystems overlap, like Maven and Clojars or the various Linux distro repos, and the same lookup doubles as a dependency-confusion check when the name exists elsewhere but the publisher does not match.",[55,175,176,179,180,185],{},[58,177,178],{},"Side-by-side package comparison."," Up to ten packages can be loaded into a ",[21,181,184],{"href":182,"rel":183},"https:\u002F\u002Fnpmx.dev\u002Fcompare",[25],"compare view"," that lays out all the metrics above in a table, plus a scatter plot with aggregate \"traction\" on one axis and \"ergonomics\" on the other so the popular-but-heavy and small-but-unknown options separate visually.",[55,187,188,191,192,197,198,201],{},[58,189,190],{},"Version diffing."," Any two published versions can be diffed file-by-file in the browser, which Hex has had for years via ",[21,193,196],{"href":194,"rel":195},"https:\u002F\u002Fdiff.hex.pm",[25],"diff.hex.pm"," and which exists in the Rust world through ",[35,199,200],{},"cargo-vet"," tooling.",[55,203,204,207],{},[58,205,206],{},"Release timeline with size annotations."," Every version of a package is plotted on a timeline with markers where install size jumped by a meaningful percentage, which is a neat way to spot the release where someone accidentally started shipping their test fixtures.",[55,209,210,213,214,219],{},[58,211,212],{},"Download distribution by version."," The weekly download chart can be broken down by major or minor line so you can see how much of the ecosystem is still on v2 of something now on v5, similar to ",[21,215,218],{"href":216,"rel":217},"https:\u002F\u002Frubygems.org\u002Fgems\u002Frails\u002Fversions",[25],"RubyGems' per-version download counts"," but rendered as a distribution rather than a table.",[55,221,222,225,226,229],{},[58,223,224],{},"Command palette."," ",[35,227,228],{},"⌘K"," opens a palette with every action available on the current page plus global navigation, and on a package page typing a semver range filters the version list to matches. Borrowed from editors and from GitHub itself rather than from any registry.",[55,231,232,235,236,241,242,247],{},[58,233,234],{},"Internationalisation."," The interface ships in ",[21,237,240],{"href":238,"rel":239},"https:\u002F\u002Fgithub.com\u002Fnpmx-dev\u002Fnpmx.dev\u002Ftree\u002Fmain\u002Fi18n\u002Flocales",[25],"over thirty locales"," including RTL languages, with ",[21,243,246],{"href":244,"rel":245},"https:\u002F\u002Fhosted.weblate.org\u002Fprojects\u002Fpypa\u002Fwarehouse\u002F",[25],"PyPI's Warehouse"," being the other registry that has invested in this.",[55,249,250,253,254,67,257,260,261,266],{},[58,251,252],{},"Accessibility as a default."," Charts and demo videos in the release notes carry long-form ",[35,255,256],{},"aria-label",[35,258,259],{},"figcaption"," text, the command palette works with screen readers, and there is a dedicated ",[21,262,265],{"href":263,"rel":264},"https:\u002F\u002Fnpmx.dev\u002Faccessibility",[25],"accessibility statement",".",[55,268,269,272],{},[58,270,271],{},"Playground link extraction."," StackBlitz, CodeSandbox, CodePen, JSFiddle, and Replit links found in a package's README are pulled out into a dedicated panel so you can try the thing without cloning it.",[55,274,275,278,279,284],{},[58,276,277],{},"Agent skill detection."," Packages that contain ",[21,280,283],{"href":281,"rel":282},"https:\u002F\u002Fwww.anthropic.com\u002Fnews\u002Fskills",[25],"Agent Skills"," manifests have them listed with declared tool compatibility, which is very 2026, though detecting non-code payloads in published packages is useful.",[55,286,287,290,291,296,297,302,303,308],{},[58,288,289],{},"Social features on AT Protocol."," Package \"likes\" are ",[21,292,295],{"href":293,"rel":294},"https:\u002F\u002Fatproto.com",[25],"atproto"," records rather than rows in a private database, blog comment threads are Bluesky threads, and the custom record types are ",[21,298,301],{"href":299,"rel":300},"https:\u002F\u002Fgithub.com\u002Fnpmx-dev\u002Fnpmx.dev\u002Ftree\u002Fmain\u002Flexicons",[25],"public lexicons in the repo"," so other tools can read and write the same data without talking to npmx. If you have ever wanted to add reviews or comments to a registry and balked at the moderation burden of running another silo, borrowing an existing network's identity and content layer is a defensible answer, and while I am personally sceptical that leaning on Bluesky's infrastructure will work out long term, npmx at least runs ",[21,304,307],{"href":305,"rel":306},"https:\u002F\u002Fnpmx.dev\u002Fpds",[25],"its own PDS at npmx.social"," so the records stay under their control either way.",[55,310,311,314,315,318],{},[58,312,313],{},"Local-CLI admin connector."," Management actions like claiming a package name or editing access are proxied through your local ",[35,316,317],{},"npm"," CLI rather than requiring you to log into the site, which sidesteps the need for npmx to hold credentials for a registry it does not own.",[55,320,321,324],{},[58,322,323],{},"Dark mode and custom palettes."," Listed last because this is the one npm has now copied, joining pkg.go.dev, crates.io, and PyPI which already had it.",[326,327],"hr",{},[17,329,330,331,336],{},"Someone in the .NET world has already built an equivalent: ",[21,332,335],{"href":333,"rel":334},"https:\u002F\u002Fnugx.org\u002F",[25],"nugx.org",", in its own words \"inspired by npmx\", is doing the same thing for NuGet.",{"title":338,"searchDepth":339,"depth":339,"links":340},"",2,[],"https:\u002F\u002Fnesbitt.io\u002F2026\u002F04\u002F16\u002Ffeatures-everyone-should-steal-from-npmx","nesbitt.io","tooling","2026-04-16","What happens when users design their own package registry frontend","md",false,null,{},true,"\u002Fideas\u002Ffeatures-everyone-should-steal-from-npmx",{"title":10,"description":345},"ideas\u002Ffeatures-everyone-should-steal-from-npmx","d7cMNOCpfblXboSueQ4dYFiJ1L8T-mFyN0GZm-RJm7Y",1780596104904]