One Package Manager's Storage Bill Exceeds Its Entire Maintainer Budget
In 2020, npm Inc. reported spending millions of dollars annually on cloud infrastructure to host the world's largest package registry. That same year, the company's maintainer stipend program — designed to compensate the volunteers who keep critical packages alive — amounted to a few hundred thousand dollars. The gap between what it costs to store every version of every package ever published and what the ecosystem pays the people who write that code is not just ironic. It is structural.
The npm Story That Breaks the Economics of Open Source
npm Inc. was acquired by GitHub (then Microsoft) in 2020 for what was reported to be a sum in the tens of millions. At the time, the registry served roughly 1.5 billion package downloads per week. Each download is a tarball — a compressed archive of code that gets unpacked onto a developer's machine. But those tarballs do not materialize from thin air. They live on cloud storage, and every download incurs a bandwidth cost.
The economics are lopsided. A single tarball might be a few hundred kilobytes. The cost of serving it, amortized across CDN edge nodes and origin storage, is small — fractions of a cent. But multiply that by billions of weekly downloads, and the numbers become real. Some estimates put npm's annual storage and bandwidth bill between $2 million and $5 million. The maintainer stipend program, meanwhile, has been capped at around $200,000 per year. That is a ratio of roughly 10:1 or worse.
This is not a critique of npm specifically. Every centralized package registry faces the same tension: storage costs grow with every new version, but revenue from the free tier is zero. npm offers paid Teams plans, but the vast majority of usage comes from free-tier developers. The registry effectively operates as a loss leader for Microsoft's broader developer ecosystem. But loss leaders have a way of becoming permanent burdens.
The asymmetry matters because it distorts incentives. When storage is free for publishers, there is no cost to publishing a new version for a typo fix. When bandwidth is free for consumers, there is no reason to clean up dependencies. The registry absorbs the cost, but the maintainer — the person who actually writes and fixes the code — sees none of that money. The system decouples the cost of distribution from the value of creation.
How One Registry Burned Through Cloud Credits
npm's infrastructure story is not unique, but it is illustrative. The registry has been hosted on AWS since its early days, using S3 for blob storage and CloudFront for content delivery. As of late 2024, the registry stored over 3 million packages and more than 20 million distinct versions. Each version is a separate object in S3. There is no deduplication across versions — if a package releases a new version that changes one line, the entire tarball is stored again.
The bandwidth costs are the real killer. A single popular package like lodash is downloaded tens of millions of times per week. Each download transfers roughly 500 KB of compressed data. At CloudFront's standard rates, that adds up quickly. npm has negotiated volume discounts, but the raw numbers are still substantial. Some analysts have pegged npm's annual CDN spend at $1–3 million alone.
Compare that to the maintainer budget. In 2019, npm launched the npm Maintainer Stipend Program, paying selected maintainers a modest monthly amount. The program was small — dozens of recipients, not hundreds. The total outlay per year was less than what the registry spent in a month on CDN. The message was clear: the infrastructure that enables open source consumption costs more than the open source production it supports.
This imbalance has real consequences. When npm was acquired, some maintainers expressed concern that the registry's priorities would shift toward enterprise features and away from the free tier. Those concerns were not unfounded. In 2023, npm introduced mandatory two-factor authentication for high-impact packages, a security improvement that also increased operational complexity. Every change to the registry costs money, and the money comes from somewhere — usually not the maintainers.
The Unseen Cost of Forever-Hosting Old Versions
One of the defining features of npm (and most other registries) is immutability: once a version is published, it cannot be deleted. This is a deliberate design choice to ensure reproducibility. If a package version disappears, builds that depend on it break. But immutability comes with a storage tax. Every version ever published must be stored indefinitely, even if no one downloads it.
The result is a growing mountain of orphaned data. Packages that were abandoned years ago still occupy space. Package squatting — registering a name and publishing a placeholder version — adds to the clutter. There is no garbage collection for unused packages. The registry cannot easily distinguish between a package that is rarely downloaded because it is niche and one that is rarely downloaded because it is dead.
One maintainer described a scenario where a small utility package they wrote years ago had ballooned to over 2 TB of storage across all its versions. The package itself was under 10 MB per version, but the maintainer had published hundreds of versions over a decade, and each one was stored in full. The storage cost for that single package, amortized, was likely more than the maintainer had ever earned from it.
This storage debt compounds without cleanup. Unlike a source code repository that can be pruned with git gc, a package registry has no equivalent. The only way to remove a version is to unpublish it, and that is restricted to within 72 hours of publication. After that, the version is permanent. The registry's storage grows monotonically, and the cost grows with it. This is a fundamental design trade-off between reproducibility and economics.
Registry Economics vs. Maintainer Sustainability
npm's paid plans — npm Teams and npm Enterprise — were introduced to offset infrastructure costs. Teams starts at around $7 per user per month for organizations that want private packages and more advanced features. But the free tier remains the overwhelming majority of usage. As of 2024, npm had roughly 2 million registered users, but only a small fraction were paying customers. The registry's revenue from paid plans is not public, but it is widely believed to be a fraction of total infrastructure cost.
Maintainers, meanwhile, earn near zero from the registry itself. The stipend program is the only direct payment, and it is tiny. Most maintainers rely on donations via GitHub Sponsors, Open Collective, or Patreon. A 2023 survey by the Tidelift company found that the median income from open source work among top-1000 package maintainers was under $10,000 per year. Burnout rates are high. The economics of the registry do not flow back to the people who generate the value.
Dependency on corporate sponsorship creates its own risks. npm's acquisition by Microsoft meant that the registry's budget now competes with other internal priorities inside a $200 billion company. If Microsoft decides that npm is not strategic enough, the infrastructure funding could shrink. That would leave the ecosystem in a precarious position. The same is true for other registries: PyPI is hosted by the Python Software Foundation, which relies on donations and sponsors. Crates.io is operated by the Rust Foundation, which has corporate backers but limited revenue.
The fundamental question is whether a centralized, free-at-point-of-use registry can ever be financially sustainable. The answer so far is no. Every major registry runs at a loss. The losses are subsidized by corporate entities or foundations. That works as long as the subsidies continue, but it is not a stable equilibrium. If the subsidies dry up, the registry either introduces fees, degrades service, or shuts down. None of those outcomes are good for the ecosystem.
Lessons from Package Managers That Got It Right
Not every package manager follows the same model. Cargo, the package manager for Rust, uses crates.io as its primary registry but relies heavily on CDN caching and mirroring. The Rust Foundation pays for the infrastructure, but the costs are lower because the ecosystem is smaller and more disciplined. Cargo also encourages the use of crates.io mirrors, which reduce load on the central registry. The decentralized model distributes bandwidth costs across many nodes.
PyPI, the Python Package Index, has taken a different approach. It uses a global CDN and imposes bandwidth caps on large packages. Packages over a certain size (currently 60 MB) require special approval. PyPI also encourages the use of community mirrors, especially for large-scale deployments. The Python Software Foundation runs the registry on a tight budget, and the caps help keep costs manageable. The trade-off is that some legitimate use cases are constrained.
Deno's package registry takes an aggressive caching approach. When a module is imported from a URL, Deno caches it locally and can serve it from cache on subsequent requests. The registry itself does not store every version indefinitely. Instead, it relies on the original source URLs and a metadata index. This reduces storage costs dramatically, but it also means that packages can disappear if the source goes offline. The trade-off is availability for cost.
Linux distribution package managers like apt and yum use tiered mirrors. The central repository holds the authoritative packages, but mirrors around the world cache and serve them. Users configure a nearby mirror, reducing load on the central server. The model is decentralized and resilient, but it requires active mirror administration. For most package ecosystems, the operational overhead of managing mirrors is too high.
Each model trades cost for availability. The npm model prioritizes zero-cost publishing and unlimited storage, which maximizes developer convenience but maximizes infrastructure cost. The mirror model reduces cost but adds complexity. The caching model reduces cost but risks availability. There is no free lunch. The question is which trade-offs the community is willing to accept.
What Maintainers Can Do Without Waiting for Policy
While the structural issues of registry economics are not something an individual maintainer can fix alone, there are practical steps that reduce the burden on the system and improve maintainer sustainability. First, adopt semantic versioning rigorously. Publishing a new version for every minor change inflates storage. Batch changes into fewer, well-tested releases. This reduces the number of tarballs the registry must store and serve.
Second, remove bundled dependencies. Many packages ship with vendored copies of their dependencies, which multiplies storage. Use proper lockfiles and rely on the package manager's dependency resolution instead. This not only saves space but also ensures that security updates to transitive dependencies are applied automatically. A single package that bundles lodash, for example, duplicates storage that already exists in the registry.
Third, encourage tree-shaking and dead-code elimination in your packages. Smaller packages mean smaller tarballs, which means lower bandwidth costs for everyone. This is especially important for front-end packages that are bundled into applications. Tools like Rollup and esbuild can produce optimized output that reduces package size by 50% or more. Every kilobyte saved is a kilobyte that does not need to be served from the CDN.
Fourth, advocate for registry cleanup of orphaned and squatting packages. Some registries have started policies for removing packages that have no downloads for extended periods. npm introduced a policy in 2023 to unpublish packages that have been deprecated for more than a year and have zero downloads. Supporting such policies, even when they might affect a package you published years ago, helps keep the registry lean. Storage debt is everyone's problem.
Finally, support funding models that directly compensate maintainers. GitHub Sponsors, Open Collective, and Tidelift are all platforms that channel money from users to maintainers. If every organization that depends on open source contributed even a small amount, the economics would shift. A company that saves $100,000 in development costs by using a free package could reasonably sponsor its maintainer for $1,000 per year. The math works. The cultural shift is harder.
The story of npm's storage bill exceeding its maintainer budget is not a scandal. It is a symptom of a system designed for convenience, not sustainability. The convenience is real — it is why millions of developers use npm every day. But the sustainability gap is real too. Fixing it will require changes from registries, from corporate sponsors, and from maintainers themselves. No single change will solve it. But ignoring it will only make the gap wider.