The Average Lifespan of an npm Package 2026
TL;DR
The median npm package last receives an update within 18 months of being published — after that, it's likely abandoned. The top 1% of packages survive and thrive for 10+ years. The other 99% either solve a very narrow problem (no updates needed) or get abandoned when maintainer interest wanes. The survival predictors: corporate backing, multiple active contributors, or solving a genuinely evergreen problem. Popularity alone doesn't predict survival.
Key Takeaways
- 50% of packages: last update within 18 months of publish
- Top 1%: 10+ year packages (React, lodash, Express, jQuery)
- Corporate backing is the strongest survival predictor
- "Solved" packages (uuid, semver) survive long with minimal maintenance
- The danger zone: packages 2-5 years old with a single maintainer
The npm Package Lifecycle
Phase 1: Launch (0-3 months)
→ Author publishes to solve a specific problem
→ If it gets traction: stars accumulate, issues filed
→ Most packages die here: no traction, no motivation to maintain
→ ~50% of packages: never updated after initial publish
Phase 2: Early maintenance (3-18 months)
→ Author still motivated: responding to issues, shipping features
→ Community grows if useful
→ ~30% of packages: last updated in this window
→ After 18 months, the probability of another update drops significantly
Phase 3: Survival or stagnation (18 months - 3 years)
→ Survivors: have user community, maintainer still invested, or corporate backing
→ Stagnators: author moved on, or problem was so well-solved no changes needed
→ ~10% of npm packages survive to 3 years with meaningful activity
Phase 4: Long-term maintenance (3-10+ years)
→ The packages that become infrastructure
→ Changes slow dramatically (intentional stability)
→ ~1% of npm packages
→ These are the lodash/axios/Express of the ecosystem
What Predicts Long-Term Survival
Survival analysis of npm packages:
Strongest predictors of 5+ year active maintenance:
1. Corporate backing (3x survival rate vs solo):
→ React (Meta), Angular (Google), Webpack (Bytedance), Express (OpenJS Foundation)
→ Companies have financial incentive to maintain their tooling investments
→ Employee time allocated to maintenance explicitly
2. Multiple active contributors (2x survival rate):
→ Single maintainer: one life event ends the project
→ 3+ active contributors: resilient to any individual's departure
→ Contributor growth signals expanding community investment
3. Solving an evergreen problem:
→ UUID generation: will always need this
→ HTTP requests: will always need this
→ Date parsing: will always need this
→ Contrast with: "CSS-in-JS for a specific React pattern" (problem might not exist in 3 years)
4. Growing downloads (not just large):
→ Flat downloads: the problem is solved, the package is stable
→ Growing downloads: new users arriving = new value = motivation to maintain
5. Clear project scope:
→ Narrow scope = fewer breaking changes needed
→ Lodash: does utility functions (solved)
→ "Full-stack framework": scope creep → eventual abandonment
Package Categories by Typical Lifespan
Long-lived categories (10+ year packages common):
→ Utility libraries: lodash, underscore, ramda
→ HTTP servers: express, koa, fastify
→ Test runners: jest (10+ years), mocha (12+ years)
→ Build tools: webpack (11+ years), Rollup (8+ years)
→ Core utilities: semver, mime, bytes
Medium-lived categories (3-8 years typical):
→ Frontend frameworks: React (10+), Vue (9+), but many alternatives
→ ORMs: Prisma (7+), Mongoose (13+)
→ Authentication: passport (12+), but smaller auth packages churn
→ Bundler plugins: specific to bundler ecosystem lifecycle
Short-lived categories (<3 years common):
→ CSS-in-JS: fast churn, paradigm shifts
→ "Wrapper" packages: wraps another API, dies when API changes
→ Scaffold tools: create-react-app, create-vue, etc. (replaced by Vite)
→ Highly specific plugins: for specific frameworks/tools
→ AI utility packages: category too new to have established survivors
The warning sign:
→ A package in a "short-lived" category that's 3+ years old with no recent activity
→ High probability it's abandoned, problem was solved, or the category moved on
The 1000 Days Rule
Informal observation from package maintainers:
A package's maintenance commitment drops significantly after ~1000 days (2.7 years)
if it hasn't reached "institutional" status by then.
Why 1000 days:
→ The "exciting new project" phase: ~6 months
→ "Maintaining what I built" phase: ~18 months
→ "Maintaining what users need but I don't use daily": ~24+ months (harder)
→ After 1000 days: either the project runs itself, has a team, or the author moves on
Evidence for this pattern:
→ Look at GitHub commit graphs for mid-tier npm packages
→ Majority have a "high activity period" followed by cliff
→ The cliff often happens 18-30 months after launch
What gets packages past the 1000-day barrier:
1. Corporate adoption: somebody's job is now to maintain it
2. Community takeover: original author transfers to community org
3. Problem maturity: "solved" packages don't need active maintenance
4. Financial support: open collective, GitHub sponsors, sponsors program
Historical Package Graveyard (Famous Examples)
# Packages that died despite early success:
# Bower (frontend package manager):
# Launch: 2012
# Peak: 2014-2015 (most popular frontend package manager)
# Death: 2017 (deprecated by maintainers, npm took over)
# Lifespan: ~5 years, but last 3 in maintenance mode
# Grunt (build system):
# Launch: 2012
# Peak: 2013-2015
# Decline: Gulp (2013), then Webpack/Rollup (2015+) → irrelevant
# Current: still alive but ~95% smaller install base
# Jasmine (testing):
# Launch: 2010
# Peak: 2011-2014 (before Jest)
# Decline: Jest dominance from 2016
# Current: actively maintained, used in AngularJS ecosystem
# CoffeeScript:
# Launch: 2010
# Peak: 2012-2015 (compiled JS before TypeScript)
# Decline: TypeScript released 2012, won by 2018
# Current: maintained but declining — a cautionary tale
# Jade/Pug (templating):
# Jade → Pug rename in 2016 (copyright issue)
# Still maintained, but HTML templates have given way to JSX/TSX
# The pattern: packages die when the problem they solve gets absorbed
# by a bigger ecosystem player (npm absorbed Bower, React absorbed templates)
How to Evaluate a Package's Survival Probability
# Quick survival probability assessment:
# 1. Age + activity:
npm view package-name time --json | jq 'to_entries | last | .value'
# Last publish date
# 2. Download trend:
# npmtrends.com/package-name → look at 1-year chart
# Flat or growing → healthy
# Declining rapidly → migration happening
# 3. Corporate vs solo:
npm view package-name --json | jq '.maintainers | length'
# > 1 maintainer = better
# Organization: npmjs.com/org/org-name → shows team
# 4. GitHub org vs personal:
npm view package-name --json | jq '.repository.url'
# github.com/some-org/package = org-backed (better)
# github.com/username/package = solo (watch for bus factor)
# 5. OpenJS or similar foundation:
# https://openjsf.org/projects/ — hosted projects have guaranteed continuity
# Risk matrix:
# Low risk: Corporate-backed, 3+ contributors, growing downloads
# Medium risk: Solo maintainer but active, growing project
# High risk: Solo maintainer, stagnant downloads, last activity 12+ months
# Very high risk: Stagnant, declining, single maintainer, no org transfer
The Abandonment Early Warning System
The official npm deprecation notice is almost never the first signal that a package is dying — it's the last one. By the time a maintainer runs npm deprecate, they've often been mentally checked out for a year or more. Teams that learn to read the earlier signals can begin migration research while the package is still fully functional, rather than scrambling the day a deprecated warning appears in their install output.
The signals to watch, roughly in order of appearance:
First, look at commit intent, not just commit frequency. A maintainer who has shifted from feature development to exclusively bumping dependency versions is in "keeping the lights on" mode. The package isn't being invested in — it's being kept from breaking. This is not the same as a "solved" package with intentional stability; a solved package hasn't had new issues opened in years. An abandoned package has a growing backlog.
Second, watch response times on GitHub issues. If a maintainer used to respond within days and issues are now sitting unanswered for 60 or 90 days, that's a behavior change worth noting. Check the issue timestamps across the last dozen open issues — the pattern is usually obvious.
Third, track download velocity over a 6-month window. A slow, steady decline of 5–10% month-over-month is different from seasonal fluctuation. Six months of consistent decline means the ecosystem is quietly migrating away, even if no official deprecation has been announced.
Fourth, check the maintainer's GitHub profile directly. If their public activity shows active commits to other projects — especially a competing or successor package — but no activity on the package in question, the decision has effectively already been made.
Fifth, watch for language in the README that hedges toward alternatives. A note that says "for new projects, consider X" is a soft deprecation. The maintainer is signaling the direction without pulling the formal trigger.
PkgPulse's health score aggregates these signals automatically. A health score trending below 50 across three consecutive monthly snapshots is a reliable migration trigger — act on the trend, not just the current number.
How to Future-Proof Your Dependencies
The most durable dependency strategy isn't about picking the best package today — it's about picking packages where the cost of being wrong is low and the signal for "wrong" arrives early.
The core principle: prefer packages with multiple independent commercial adopters over packages maintained by a single individual. A package that Vercel ships in their framework, Cloudflare integrates into their toolchain, and three Fortune 500 companies depend on in production is not going to be abandoned without a migration path. The organizational incentive to maintain it is distributed across too many parties. A package maintained by one developer who might change careers, start a company, or simply lose interest has a single point of failure.
The practical implication: npm packages that have been adopted by major frameworks or infrastructure tools are effectively co-maintained by the ecosystem. React's dependencies, Vite's core plugins, Prisma's database adapters — these packages have organizations with engineering teams who have strong incentive to keep them working and file PRs when something breaks.
For high-risk dependency categories — date manipulation, ID generation, HTTP clients, logging — apply an abstraction layer strategy. These categories have multiple viable alternatives with relatively straightforward migration paths. If you're using date-fns and it were abandoned tomorrow, switching to dayjs or the native Temporal API is a bounded, well-understood migration. The existence of alternatives and documented migration paths reduces the cost of any individual package being abandoned.
Finally, check for explicit maintenance commitments before adopting a package. Commercial backing (Prisma), foundation stewardship (Babel, webpack through the OpenJS Foundation), and active governance documentation are all positive signals. These structures exist precisely to ensure continuity beyond any single maintainer's personal circumstances — and they've been proven to work.
Survivorship Bias and What npm Stats Don't Show You
The instinct to evaluate the npm ecosystem by its active packages produces a systematically distorted picture. When you look at download trends, maintainer activity, or version release frequency, you are only seeing the packages that survived to be counted. The abandoned packages — and there are millions of them — don't show up in install statistics once they stop appearing in new projects. They remain on npm, occupying version numbers and registry space, but they've become invisible to any measurement that counts activity.
This survivorship bias affects practical advice in meaningful ways. "The average npm package is well-maintained" is a statement about the packages that receive enough traffic to appear in ecosystem analyses. The true distribution includes the enormous long tail of zero-download packages — one-time experiments, obsolete wrappers, packages that solve problems the ecosystem moved on from. These packages are still technically "alive" in that they can be installed. They're just dead in every way that matters.
The practical implication: when you encounter a package with an unusually clean GitHub profile — good documentation, no open issues, responsive maintainer — and wonder whether the healthy appearance reflects genuine quality or simply a narrow slice of data, check the age alongside the activity. A package that launched three months ago with a clean issue tracker isn't healthy; it's new. A package that has been active for four years with a consistently clean issue tracker and regular releases is genuinely healthy. The age dimension is what separates real maturity from recency bias.
Download counts suffer from the same survivorship effect. A package with two million weekly downloads is not necessarily well-maintained — it might be deeply entrenched in the dependency trees of other packages that were themselves popular five years ago and are now declining slowly. The download count reflects historical entrenchment as much as current health. The more diagnostic number is download trend — is it growing, flat, or declining? Declining downloads from a historically high base often means the ecosystem is quietly migrating away, even if the absolute number looks impressive in isolation.
Package Lifespan by Category: What the Patterns Reveal
Package longevity varies predictably by category, and the patterns reveal something about why certain problems stay solved while others keep churning.
CLI tools that wrap external APIs or system commands have unusually long lifespans for an interesting structural reason: the external systems they wrap don't change very often, and the interfaces are simple. A CLI tool for managing SSH keys, querying DNS records, or processing CSV files solves a problem that is genuinely stable. The underlying operating system and protocol interfaces change on decade timescales. Packages in this category can achieve true "maintenance complete" status — where the package is correct and complete and genuinely doesn't require updates to remain useful.
Framework-specific wrappers have the shortest typical lifespans of any npm package category. A package that wraps a specific React class component API, provides helpers for Gatsby's plugin system, or extends a framework's configuration format is tied entirely to the lifecycle of that framework. When React moved from class components to hooks, the tooling ecosystem around class components became obsolete almost overnight. When Gatsby's market share collapsed in favor of Next.js, the Gatsby plugin ecosystem lost most of its maintenance motivation simultaneously. The wrapper's lifespan is bounded by the framework's lifespan and by the framework's API stability.
Utility libraries for universal problems — string manipulation, number formatting, deep equality checking — tend toward long lifespans when they accumulate enough dependents. The problem they solve doesn't change; the inputs and outputs are consistent across JavaScript environments; and once a package is embedded in enough other packages' dependency trees, the maintenance motivation shifts from "I use this" to "the ecosystem depends on this." Semver, mime-types, and is-buffer all reached this state years ago. They're not maintained because anyone is enthusiastic about them — they're maintained because the cost of an unmaintained version rippling through the ecosystem is too high to ignore.
Authentication and security packages live in an intermediate zone. Passport.js is twelve-plus years old and still actively maintained because security packages accumulate trust slowly — developers are deeply conservative about replacing authentication infrastructure that works — and because the problem domain (authenticating users) is genuinely evergreen. But smaller auth utilities, particularly those that wrap specific OAuth provider APIs, churn constantly as providers update their auth flows. The auth package longevity split is really about who the maintainer's dependency is: packages that solve the core protocol problem live long; packages that wrap a commercial provider's specific implementation live as long as that provider's API is stable.
"Maintenance Complete" vs Abandoned: A Meaningful Distinction
The framing of any unmaintained package as "abandoned" misses an important subcategory: packages that are genuinely complete and correct, where no further updates are the appropriate response to the state of the code.
uuid is a useful case. UUID generation follows an RFC specification that has been stable for years. The v4 UUID algorithm is a deterministic function of random bytes. The package needs to stay compatible with current Node.js versions, and it occasionally releases patches to address edge cases in specific environments — but its fundamental job is done. A package like this doesn't require active development; it requires custodianship. Someone to watch Node.js LTS changes, handle environment-specific bugs, and keep the npm metadata current. The absence of frequent releases is a feature, not a bug.
semver is an even cleaner example. The semver package implements the Semantic Versioning specification. When the spec is stable, the implementation should be stable. Frequent releases to the semver package would be concerning — what problem requires constant changes to the core version parsing logic? The fact that it releases infrequently and has almost no open issues means it's correctly implementing a stable spec. This is the package equivalent of a finished book: it does what it's supposed to do, nothing needs adding, and editing it would be more likely to introduce errors than improvements.
The distinction that matters for consumers: a maintenance-complete package has no open issues that represent real bugs, shows compatibility with current Node.js LTS versions, and documents itself as stable or feature-complete. An abandoned package has open issues describing real bugs with no responses, may show compatibility problems with current runtimes, and has a maintainer who has gone silent. These look similar from a distance — both have few recent commits — but they are fundamentally different situations.
The tell for maintenance-complete status is the issue tracker. A package that has been around for five years with twelve open issues, all of which are feature requests the maintainer has explicitly declined, is healthy. A package with twelve open issues where three report crashes, two report compatibility failures with Node 20+, and none have maintainer responses is not healthy. PkgPulse's health scoring accounts for this distinction by weighting issue type alongside issue count — a zero-response crash report is weighted more heavily than a feature request the maintainer has actively chosen not to implement.
The Bus Factor Problem in the npm Ecosystem
The bus factor — the number of people who need to be unavailable before a project stalls — is the dominant structural vulnerability in the npm package ecosystem. The majority of npm packages that are actively maintained have a bus factor of exactly one. This is not because solo maintainers are reckless; it's because the npm ecosystem provides no institutional structure for continuity beyond what individual maintainers voluntarily establish.
The consequences are routine. A maintainer changes jobs and their new employer's NDA creates concerns about contributing to the old project. A family event consumes their bandwidth for months. A burnout period follows years of unpaid maintenance work. In each case, the project stalls — not from any decision to abandon it, but from a gap in available time that no organizational structure exists to fill. Packages with dozens of millions of weekly downloads become effectively unmaintained because their sole active maintainer got busy.
The OpenJS Foundation and similar governance structures exist precisely to address this. Foundation-hosted projects have transfer processes, governance documentation, and sometimes paid stewardship. When a sole maintainer of an OpenJS-hosted project needs to step back, there's a structure for recruiting a replacement or a committee of maintainers, rather than letting the project stall. Express, webpack, and several other foundational packages have foundation stewardship that makes their continuity far more resilient than solo-maintained packages of equivalent popularity.
The practical evaluation: before adopting a package with high bus factor risk, check whether a contingency path exists. An organizational npm account (versus a personal account) indicates institutional rather than individual ownership. Documented governance or contributing guide indicates structured succession planning. Multiple maintainers in the npm metadata increases resilience proportionally. Transfer agreements documented in the README — some maintainers explicitly state "if this package becomes unmaintained, ping X or Y to pick it up" — are rare but meaningful signals that the maintainer has thought about continuity.
The asymmetry of bus factor risk: the cost of a high-bus-factor package failing is proportional to how deeply you've integrated it, not to the package's popularity. A deeply integrated authentication library with a single maintainer is a higher-risk dependency than a deeply integrated HTTP client with five active corporate contributors. Both might have similar download counts, but their resilience to the bus factor problem is fundamentally different. Evaluating bus factor should happen before adoption, not after the package enters your codebase at depth.
How Lifespan Expectations Should Change Package Selection
Understanding typical package lifespans by category changes how to think about dependency selection decisions. The goal is not just to pick the best package today but to pick packages where the probability of being forced into an unplanned migration is lowest.
For dependencies in short-lifespan categories — framework-specific wrappers, CSS-in-JS utilities, experimental state management — the selection calculus should weight abstraction and migration cost differently than for long-lifespan categories. A package in a category with high churn rate should be adopted behind a thin abstraction layer: a single file in your codebase that wraps its API, so that when (not if) a better alternative emerges, the migration is confined to one file rather than distributed across dozens of call sites. This is not defensive programming in the pejorative sense — it's acknowledging that the category's history predicts future churn and designing accordingly.
For dependencies in long-lifespan categories — HTTP servers, testing frameworks, utility libraries with decades-long track records — the selection calculus can weight current quality more heavily because the switching cost is lower in the long run. Express and Fastify are both in a category with proven longevity; the category risk is low, so the comparison reduces to current capability and maintainer quality. Zustand and Jotai are both in the React state management category, which has higher historical churn; the selection deserves more caution about lock-in, even though both packages are currently well-maintained.
The most defensible long-term dependency choices are packages that solve problems the runtime itself is unlikely to absorb. Node.js's stdlib is expanding — crypto.randomUUID() eliminated the need for many uuid use cases, structuredClone eliminated many lodash.cloneDeep use cases. Before adopting any package, checking whether the problem is on the trajectory toward being solved natively is worthwhile: if Node.js or the web platform is actively working on a native solution, the package's effective lifespan ends when that solution ships. The Temporal API's imminent full adoption means any date library should be evaluated with the awareness that the native alternative is arriving. Packages that wrap platform capabilities that will be native soon have a structural lifespan limit regardless of their current maintenance quality.
Compare package health scores and maintenance data at PkgPulse.
See also: Package Maintenance Scores: Who and npm Packages with the Fastest Release Cycles, How GitHub Stars Mislead Package Selection.
See the live comparison
View fastify vs. express on PkgPulse →