npm Is Not Just a CLI
The npm registry exposes a free JSON API. No API key, no OAuth, no rate limits for reasonable usage. Every package on npm has a JSON endpoint.
Get Package Metadata
const res = await fetch("https://registry.npmjs.org/express");
const pkg = await res.json();
console.log(`${pkg.name} — ${pkg.description}`);
console.log(`Latest: ${pkg["dist-tags"].latest}`);
console.log(`Versions: ${Object.keys(pkg.versions).length}`);
console.log(`License: ${pkg.license}`);
Get Specific Version
const res = await fetch("https://registry.npmjs.org/react/19.0.0");
const version = await res.json();
console.log(`Dependencies:`, Object.keys(version.dependencies || {}));
console.log(`Size: ${version.dist.unpackedSize} bytes`);
console.log(`Tarball: ${version.dist.tarball}`);
Get Download Counts
// Last week downloads
const res = await fetch("https://api.npmjs.org/downloads/point/last-week/express");
const data = await res.json();
console.log(`${data.package}: ${data.downloads.toLocaleString()} downloads/week`);
// Daily breakdown
const range = await fetch("https://api.npmjs.org/downloads/range/last-month/express");
const daily = await range.json();
daily.downloads.forEach(d => console.log(`${d.day}: ${d.downloads.toLocaleString()}`));
Compare Packages
async function comparePackages(names) {
const results = await Promise.all(
names.map(async name => {
const [meta, downloads] = await Promise.all([
fetch(`https://registry.npmjs.org/${name}`).then(r => r.json()),
fetch(`https://api.npmjs.org/downloads/point/last-week/${name}`).then(r => r.json())
]);
return {
name,
version: meta["dist-tags"].latest,
weekly: downloads.downloads
};
})
);
results.sort((a, b) => b.weekly - a.weekly);
results.forEach(r =>
console.log(`${r.name.padEnd(20)} v${r.version.padEnd(10)} ${r.weekly.toLocaleString()}/week`)
);
}
await comparePackages(["express", "fastify", "hono", "koa", "nest"]);
Search Packages
const res = await fetch("https://registry.npmjs.org/-/v1/search?text=web+scraping&size=5");
const data = await res.json();
data.objects.forEach(obj => {
const p = obj.package;
console.log(`${p.name} — ${p.description?.slice(0, 60)}`);
});
Real Use Cases
- Dependency dashboards — monitor all your deps for new versions
- Security scanning — check package sizes for supply chain attacks
- Ecosystem analytics — track framework adoption trends
- CI/CD — auto-detect outdated packages in PRs
- Tech radar — compare alternatives by download trends
More from me: 10 Dev Tools I Use Daily | 77 Scrapers on a Schedule | 150+ Free APIs
Top comments (0)