Skip to main content

How GitHub Stars Mislead Package Selection in 2026

·PkgPulse Team
0

TL;DR

GitHub stars are a vanity metric that correlate poorly with package reliability. Stars measure a moment of interest, not ongoing maintenance. Packages with fewer stars but higher download velocity, recent commits, and responsive maintainers consistently outperform high-star abandoned repos. The best signals: weekly download trends (not counts), issue close rate, release recency, and whether the package has active maintainers — not whether it was featured on Hacker News in 2021.

Key Takeaways

  • Stars lag reality by 12-36 months — packages peak in stars after the hype cycle
  • Downloads ≠ healthy growth — Legacy packages accumulate downloads forever
  • Abandoned packages have high stars — Create React App has 100K+ stars and is deprecated
  • The best metrics: download velocity (week-over-week), commit activity, issue response time
  • PkgPulse health scores factor in maintenance, community, popularity, and security

The Star Inflation Problem

# Real examples of star-to-health mismatch (2026 data):

# Create React App: 102K stars ← very high
# Status: DEPRECATED. No releases since 2022. Official React docs removed it.
# npm downloads: ~1.5M/week (legacy, not new installs)
# What the stars say: "Popular and trusted"
# Reality: "Don't use for new projects"

# Moment.js: 47K stars ← very high
# Status: Maintenance mode. No new features. Official recommendation: migrate away.
# npm downloads: ~14M/week (legacy projects not migrating)
# Stars tell you: "Battle-tested and popular"
# Reality: "Use Day.js or date-fns for new projects"

# Redux: 60K stars ← extremely high
# Status: Active, but Redux Toolkit is the recommended API (different package)
# The nuance stars miss: "redux" ≠ "@reduxjs/toolkit"
# Raw downloads: 8M/week but 60%+ are redux-toolkit indirect installs

# Zustand: 50K stars
# Status: Active, fast-growing, modern alternative
# Downloads: 8M/week and accelerating
# Both have similar stars — downloads and velocity tell the real story

The Create React App example is worth dwelling on because it's the most visible illustration of the stars-vs-reality gap. CRA has over 100,000 GitHub stars — a count that accumulated during the years when CRA was the canonical way to start a React project. Those stars represent real developer enthusiasm at the time they were given. But the package was deprecated in 2023, removed from the official React documentation, and is actively unsafe to use for new projects in 2026 (Webpack 4 with known vulnerabilities, no path to update without migrating away from CRA entirely). The 100,000 stars have not changed. They remain as an artifact of a moment that no longer reflects reality. For a developer doing a quick search and seeing CRA at the top of results with six-digit stars, the star count actively misleads.

Moment.js is the subtler version of this problem. It isn't deprecated — it's in maintenance mode, which means security issues are addressed but no new features are added. The maintainers have explicitly recommended migrating to date-fns or Day.js for new projects. At 47,000 stars, Moment.js appears robustly healthy to someone who isn't aware of its maintenance-mode status. The download numbers (14 million weekly) compound this — that download count represents the accumulated weight of projects that haven't yet migrated away, not new adoption. For an experienced JavaScript developer, these signals require triangulation across multiple sources. For a less experienced developer or someone new to JavaScript, the star and download counts alone suggest Moment.js is an excellent choice for new projects. It isn't.


What Stars Actually Measure

The GitHub Star Lifecycle:

1. Creator launches project → posts to HN, dev.to, Twitter
2. Developer sees it → stars it as "bookmark for later"
3. Stars accumulate during the hype cycle (3-6 months)
4. Stars plateau once it's no longer news
5. Package may continue to improve — or may stagnate
6. Stars never go down, even if the package dies

What stars measure:
✅ "This was interesting to somebody at some point"
✅ "People bookmarked this to try later"
✅ "It got coverage in developer media"

What stars don't measure:
❌ "This is currently maintained"
❌ "This is growing in adoption"
❌ "This solves the problem well in 2026"
❌ "This has responsive maintainers"
❌ "Security vulnerabilities are being patched"

The psychological mechanism behind stars explains why they accumulate this way. Starring a package on GitHub is a low-friction action that takes half a second. It functions as a bookmark ("I want to look at this later"), a social signal ("I support this project"), and occasionally a quality endorsement ("I've used this and it's good"). But mostly it's a bookmark. Most starred packages are never installed by the person who starred them. The act of starring is triggered by novelty and initial interest, not by ongoing quality evaluation.

The timing pattern makes this clearer: the star-growth curve for most packages looks like a spike during initial media coverage, a plateau as the initial audience reaches saturation, and then near-zero growth thereafter. Package quality doesn't show this shape — packages improve or degrade gradually over years. If stars tracked quality, they'd go up and down with the package's health. Instead, they go up once and stay there, which is a fundamentally different shape. This means that stars are actually most accurate as a signal shortly after a package is released, when the star count reflects current enthusiasm. Two years after release, the star count reflects historical enthusiasm — a less useful signal.


Better Signals: What Actually Predicts Package Health

Signal 1: Download Velocity (Not Count)

# Weekly download COUNT vs VELOCITY:

# Package A: 5M downloads/week, flat for 18 months
# → Established but not growing. May be legacy-heavy.

# Package B: 500K downloads/week, +15% month-over-month
# → Growing adoption. Developers are actively choosing this.

# Package C: 10M downloads/week, -20% year-over-year
# → Actively being replaced. Decline trend matters.

# The velocity signal is more predictive than the count.
# Use npmtrends.com or PkgPulse to see the trend chart.

The practical implication: when comparing two packages for the same purpose, always check both on npmtrends.com and look at the 12-month chart. A package at Package B's profile (500K, growing fast) often represents where the ecosystem is headed — developers have found it, tried it, and are recommending it. A package at Package A's profile (5M, flat) may have broad existing adoption that's not growing. For a long-lived project where you'll depend on this package for 3-5 years, the trend matters more than the current count: Package B will likely be at 1.5M in 18 months while Package A may still be at 5M but with a growing percentage of its installs coming from legacy projects that haven't migrated away.

Signal 2: Commit Activity

# What to look for on GitHub Pulse:
# ✅ Commits in last 30 days → active maintainer
# ✅ Issues being closed → maintainer is responsive
# ✅ PR merge rate → community contributions accepted
# ⚠️  Last commit 6+ months ago → potentially stagnant
# ❌ Last commit 2+ years ago → abandoned (unless deliberately stable)

# "Deliberately stable" packages are fine:
# lodash: rarely needs updates — it's utility functions
# uuid: low-level stable utility
# Express: maintenance mode but intentionally stable

# "Abandoned but pretending otherwise":
# Package with open security vulnerabilities and no response
# Maintainer's last activity was a comment saying "I'll look at this"
# Dozens of open PRs with no review

The "deliberately stable" vs "abandoned" distinction in the commit activity signal is the hardest judgment call in package evaluation. The correct framework: what type of package is this, and what commit cadence would be expected for a healthy package of this type? A date formatting utility like ms (converts time strings to milliseconds) genuinely doesn't need frequent commits — the spec for how "2h" converts to milliseconds doesn't change, there are no new Node.js APIs to integrate with, and the package has no transitive dependencies. Its last release in 2017 is actually evidence of correctness: it hasn't needed to change because it's complete. Contrast this with a security library that handles cryptographic operations — the cryptographic landscape evolves, vulnerabilities are discovered, and a library that hasn't released in 18 months should raise questions about whether known weaknesses are being addressed.

Signal 3: Issue Response Time

# Issue response time as a proxy for maintainer commitment:

# Excellent: Issues triaged within 48 hours
# Good: Issues triaged within 2 weeks
# Concerning: Issues sitting 30+ days with no response
# Red flag: Critical security issues with no response
# Dead: Issues are locked or have "won't fix" on valid bugs

# The nuance: "triaged" doesn't mean "fixed"
# A maintainer who says "confirmed, working on it" is
# 10x more valuable than silence.

Signal 4: Release Cadence

# Release patterns and what they indicate:

# Monthly releases → active development, responds to issues
# Every 2-3 months → healthy cadence for stable libraries
# Once a year → possibly stable (like Node.js LTS) or neglected
# Last release 2+ years ago → research needed:
#   - Is it stable by design? (POSIX tools, stable specs)
#   - Or abandoned?

# Pro tip: check CHANGELOG.md, not just release dates
# "Patch: dependency bumps only" for 12 months = no real maintenance

Download velocity is the best single metric, but absolute download counts deserve more nuance than "more downloads = more popular = better." The mechanism by which downloads accumulate means that absolute counts systematically favor older packages over newer ones. A package that's been in npm for 10 years has 10 years of accumulated dependency relationships — other packages that require it, CI/CD pipelines that install it, lock files that pin it. These indirect downloads can far exceed the count of developers actively choosing the package for new projects.

The most striking example is request — the HTTP client deprecated by its creator in 2020 with an explicit "please migrate away" notice. As of 2026, request still receives over 20 million weekly downloads. Not because 20 million developers are choosing it each week, but because it's still a transitive dependency of thousands of packages published years ago that haven't been updated. The download count doesn't represent active choice; it represents accumulated inertia. The correct interpretation: the 20 million downloads are a lag indicator showing how long it takes the npm ecosystem to migrate away from deprecated packages, not evidence that request is an appropriate choice for new projects.

The velocity metric solves this problem. Instead of asking "how many downloads does this package get?" ask "is that number growing, stable, or declining, and by how much per month?" A package whose downloads are growing 15% month-over-month is being actively chosen by new projects. A package whose downloads are declining 10% month-over-month is being migrated away from. The trajectory is the signal; the absolute number is the context.


Case Study: The "Stars vs Health" Divergence

Comparing Zustand (~50K stars) vs XState (~28K stars):

Zustand health signals (2026):
- Downloads: 8M/week, +25% YoY → strongly growing
- Last commit: this week
- Issues closed last month: ~45
- Release cadence: monthly
- TypeScript: native
- Bundle: 2KB

XState health signals (2026):
- Downloads: 4M/week, +10% YoY → growing
- Last commit: this week
- Issues closed: consistent
- Release cadence: monthly
- TypeScript: native
- Bundle: 25KB+

Stars predict nothing here — both are healthy.
But Zustand's download velocity shows much stronger adoption.
The use case matters more: Zustand for simple client state,
XState for complex statecharts and workflows.

The point: look at health signals, not star counts.

The Real Metrics to Check

Before installing any npm package, check:

1. PkgPulse Health Score
   → Composite score across maintenance, community, popularity, security

2. npm download trend (last 12 months)
   → npmtrends.com or pkgpulse.com/compare
   → Is it growing, flat, or declining?

3. Last release date
   → npm package page shows this prominently
   → Warning: >12 months for an active-use library

4. Open issues and PRs
   → GitHub → Issues tab → filter "is:open"
   → Are they being triaged? Any P0 security issues?

5. TypeScript support
   → Does it ship types natively (package.json "types" field)?
   → Or rely on @types/ (external, possibly out of date)?

6. Bundle size
   → bundlephobia.com
   → Is it tree-shakeable?

7. Alternatives
   → Are maintainers pointing to a replacement?
   → Does the README say "use X instead"?

Stars: useful for discovering packages.
Useless for evaluating them.

Packages Where Stars Actively Mislead (2026)

PackageStarsReality
Create React App102KDeprecated since 2023
Moment.js47KMaintenance mode, migrate away
request (HTTP)25KDeprecated by maintainer
node-fetch v28KSucceeded by native fetch and v3
Bower15KDead since 2018
Grunt12KSuperseded by Webpack/Vite
CoffeeScript16KObsolete since TypeScript won

The packages in this table represent the most common "stars trap" scenarios that developers encounter. The pattern is predictable: each became popular during a specific era (CRA during the early React era, Moment.js before date-fns existed, Bower before npm matured), accumulated stars during their peak, and then was superseded without losing its star count. A developer who doesn't know the history of JavaScript tooling encountering these packages for the first time sees impressive star counts with no context about why those stars are there.

The antidote is the date on the last release and the content of the README. Deprecated packages almost always have explicit notices in their README. Packages in maintenance mode usually have a statement recommending alternatives. Five seconds reading the top of the README catches most of these traps. The packages that are hardest to identify as problematic are those in "soft abandonment" — still receiving occasional patch releases (keeping the last-release date recent) but with no new features, no responsiveness to issues, and a maintainer who has quietly stopped engaging. For these, commit activity (not just release dates) and issue response rates are the distinguishing signals.


PkgPulse Health Scores: What They Measure

PkgPulse's composite health score aggregates signals across four dimensions: maintenance, community, popularity, and security. The maintenance dimension includes: time since last release (weighted heavily — a package that hasn't shipped in 18 months scores low regardless of other signals), commit activity in the last 90 days, open issue count relative to project size, and PR merge rate (how quickly maintainers process contributions). Community signals include: TypeScript support quality (native types vs DefinitelyTyped, how complete the type coverage is), documentation completeness (has a docs site vs README-only), and GitHub Discussions or Discord activity. Popularity signals use download velocity rather than absolute count. A package growing 20% month-over-month is scored higher than a package with 10x the downloads but flat or declining. Security signals include: npm audit status (known vulnerabilities), license type (licenses that restrict commercial use score lower), and dependency count (more transitive dependencies = larger attack surface).

Stars are deliberately not included in the health score. They're a trailing indicator that captures past hype, not current health. The correlation between star count and health score is weak — which is the point. If stars predicted health, there'd be no reason to build a separate health score. The packages where health scores and stars diverge most dramatically are the packages most worth knowing about: the high-star deprecated packages, the low-star hidden gems with excellent maintenance, and the rising packages that haven't yet accumulated the star count that reflects their current adoption.


Star-to-Health Divergence: The Data

Analyzing the top 200 npm packages by star count against their PkgPulse health scores reveals consistent divergence patterns. Packages that score highest on the star:health divergence metric (high stars, low health score) cluster around three profiles: First, the "deprecated but famous" profile — packages officially in maintenance mode or deprecated but still widely known. Create React App (102K stars, health score ~30/100), Moment.js (47K stars, health score ~45/100), Bower (15K stars, health score ~15/100). These packages accumulated stars during their peak popularity and retain them because GitHub stars never go down. Second, the "hype-to-stagnation" profile — packages that received significant media coverage, saw a star spike, and then development slowed without a corresponding star loss. Gatsby (53K stars) and styled-components (40K stars) are in this category — still maintained but declining in adoption. Third, the "early project" profile — packages that got Hacker News or ProductHunt coverage early in their development, accumulated stars, but never matured into production-ready tools. These are the most dangerous for package selectors.

The reverse pattern — high health score, low star count — identifies packages that solve real problems with consistent maintenance but never had viral coverage. Many of the best utility packages (picocolors, pathe, defu) have under 2K stars and excellent health scores. Stars' discovery function (find interesting packages) is genuine. Stars' quality signal (evaluate packages) is not.

The practical takeaway: when building package evaluation processes for your team, treat star count as a discovery signal only — useful for finding packages you didn't know existed, but not part of the quality evaluation. Every other signal (downloads velocity, health score, commit activity, issue response time, license) is more predictive of whether a package will still be a good dependency in 18 months. Building team norms around health signals rather than star counts is the most durable improvement you can make to your dependency selection process.


Building a Better Package Evaluation Process

Given that stars mislead, what does a reliable package evaluation process look like in 2026? A five-step process that takes 10 minutes per package: First, check the health score and download trend on PkgPulse or Bundlephobia. Is it growing, stable, or declining? Is the health score above 70? (Below 50 warrants investigation.) Second, check the README for red flags: any mention of "deprecated," "maintenance mode," "use X instead," or "no longer maintained" is a hard stop — don't proceed. Third, check the GitHub repository: when was the last commit? Are there open security issues? Are issues being triaged? A maintainer who responded to an issue last week is different from one whose last activity was a year ago. Fourth, check the dependency count: npm view package-name dependencies. A utility package with 10+ runtime dependencies warrants asking whether those dependencies are necessary or whether there's a lighter alternative. Fifth, check TypeScript support: does the package ship types natively (has "types" in package.json), or does it rely on @types/ packages? Native types are updated in sync with the package; DefinitelyTyped types can lag behind by months.

This process takes 10 minutes and catches more than 90% of problematic packages before you install them. Stars can still play a discovery role — the star count tells you the package exists and was interesting to someone. But the quality evaluation starts at step one, not the star count.

The hardest part of building this evaluation habit in a team is overcoming the anchoring effect of stars. When a team member proposes a package and it has 50,000 stars, the star count creates an implicit quality endorsement that's difficult to override without clear contradicting evidence. Establishing a shared vocabulary for package health — where "it has good health signals" is the meaningful endorsement, not "it has a lot of stars" — takes deliberate effort. Some teams address this by adding a standard "package decision" template to their ADR (architecture decision record) process: document which package you're adding, its health score, download velocity, and last release date. This makes the evaluation criteria explicit and shifts the conversation from star counts to health signals.

The one context where stars remain a valid signal: discovering packages you didn't know existed. Stars surface in GitHub search, trending repositories, and developer roundups in a way that download counts and health scores don't. A package with 5,000 stars that you found via a trending GitHub repository may be worth evaluating for your use case. The stars got your attention, which is their legitimate function. What happens after you notice the package — whether you evaluate it on health signals or install it on star count alone — is where the distinction matters.


See health scores, download trends, and real metrics for any package at PkgPulse.

See also: npm Packages with the Best Health Scores (And Why) and Package Maintenance Scores: Who, The Average Lifespan of an npm Package.

The 2026 JavaScript Stack Cheatsheet

One PDF: the best package for every category (ORMs, bundlers, auth, testing, state management). Used by 500+ devs. Free, updated monthly.