Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Packagist Stats Laravel Package

graham-campbell/packagist-stats

A PHP package by Graham Campbell for retrieving Packagist statistics, including download counts, through a simple, framework-agnostic API. Installable via Composer and easy to integrate with Laravel or any PHP application.

View on GitHub
Deep Wiki
Context7

Getting Started

This is an end-user CLI tool, not a library — you "leverage" it by running the binary, not by importing classes into your app. There are no dependents and no public API surface worth integrating against, so treat it like composer or artisan: something on your PATH.

Install globally (recommended):

composer global require graham-campbell/packagist-stats

Then confirm the Composer global bin directory is on your PATH:

# macOS / Linux (Composer 2)
export PATH="$HOME/.config/composer/vendor/bin:$PATH"   # Linux / newer macOS
export PATH="$HOME/.composer/vendor/bin:$PATH"           # older setups

Where to look first:

  1. packagist-stats --help (or packagist-stats list if it's a Laravel Zero build) — this is authoritative for the command name and argument signature, which is the one thing that varies between releases of tools like this.
  2. The command signature itself, typically packagist-stats <vendor/package> [<vendor/package> ...]. The underlying data is the public Packagist endpoint https://packagist.org/packages/{vendor}/{name}.json, so the numbers you see are package.downloads.total and package.downloads.monthly.

First real use case — baseline before a release. Run it against your own package the day before you tag, record the total, then run it again a week after. That delta is the only honest measure of whether a release announcement, a README rewrite, or a Packagist homepage slot actually moved anything.

packagist-stats laravel/framework
packagist-stats graham-campbell/packagist-stats

Implementation Patterns

1. Dependency vetting before composer require

The single highest-value pattern. When choosing between two packages, total downloads alone are misleading (age dominates). Compare monthly downloads against the alternatives and against the package's own total to sanity-check momentum:

packagist-stats spatie/laravel-permission \
                spatie/laravel-permission-ui \
                owen-it/laravel-auditing

A package with 5M total but 2k monthly is coasting; a package with 500k total but 400k monthly is on fire. Read the ratio, not the headline number.

2. Post-release regression check

Wire it into your release checklist as a Makefile/Taskfile target so it's one keystroke, not a browser trip:

stats:
	packagist-stats $(PACKAGE)

Then make stats PACKAGE=vendor/name before and after tagging. Combine with composer show -s for the local version and commit hash, so the snapshot in your release notes is reproducible.

3. Comparing internal packages in a monorepo

If you split a monorepo into read-only subtree splits, you almost certainly have packages that no one installs because the docs point at the umbrella package. Batch-run the whole set to find dead splits:

for pkg in $(jq -r '.replace | keys[]' composer.json); do
  packagist-stats "$pkg"
done

This is the practical way to decide whether a split package is worth the CI minutes.

4. Scheduled snapshot in CI

Because the tool is a thin wrapper over a public JSON endpoint, the most durable integration is a weekly scheduled job that appends to a file and diffs it. You can either shell out to this binary or skip it and hit the API directly — the latter is preferable if you need structured output, since the CLI is formatted for humans:

// Equivalent data, no CLI dependency
$data = Http::get("https://packagist.org/packages/{$vendor}/{$name}.json")
    ->throw()
    ->json('package.downloads');
// ['total' => ..., 'monthly' => ..., 'daily' => ...]

Use the CLI for interactive/ad-hoc work; use Http::get for anything that needs to be parsed, stored, or alerted on.

5. Triage during an incident

When a transitive dependency breaks and you're deciding whether to pin, fork, or abandon, download volume tells you whether an upstream fix is likely to arrive fast. High monthly volume → the maintainer has pressure and users reporting. Near-zero → you're on your own; plan the fork immediately.

Gotchas and Tips

Don't composer require this into a Laravel app. It's built on Laravel Zero, which pulls illuminate/* components. Requiring it as a project dependency can produce dependency-resolution conflicts against your app's framework version. Install it globally or as a standalone --dev tool in a dedicated tooling directory. The bamarni/composer-bin-plugin pattern (bin/tools) is the clean escape hatch.

PATH is the #1 "it's installed but not found" cause. composer global require succeeds, then the binary is invisible because ~/.config/composer/vendor/bin isn't exported. Check with composer global config bin-dir --absolute rather than guessing the path.

Stats are aggregate and time-windowed, not live-event. Packagist's daily figure is a rolling window and can appear to "reset" — it is not a per-day counter you can sum. Never chart daily values as if they were additive, and never treat a one-day dip as signal.

Total downloads correlate with age, hard. A four-year-old package with modest adoption will out-total a six-month-old rocket. Always cross-reference monthly, and ideally the package's time field from the same JSON response, before drawing conclusions.

Abandoned packages still serve stats. The endpoint returns numbers regardless of the abandoned flag. If you're using download counts to pick a dependency, also check abandoned in the JSON — an abandoned package with healthy monthly numbers is the worst trap because it looks maintained.

Exact naming required. vendor/name, case-insensitive but otherwise exact. Typos return a 404 that some CLI wrappers surface as a generic error; when output looks wrong, verify the URL manually with curl https://packagist.org/packages/vendor/name.json.

Rate limiting and caching. There's no auth and no documented quota you should test. Batch loops over dozens of packages should sleep between calls, or hit the API once and cache to disk for the session. Repeatedly running the CLI in a tight loop is the fastest way to get throttled.

Output is human-oriented — don't parse it. If you find yourself grep-ing or awk-ing the CLI output in a script, stop. That formatting is cosmetic and will change without notice. Drop to the Packagist API for anything machine-consumed.

Extension point is the source, not config. As a Laravel Zero app, the natural way to add behaviour (JSON output, extra metrics like favers, historical storage) is to fork and add a command class rather than to look for a config file. Given the package's size and zero-dependents status, expect a fork to be the maintenance path if you need it in production tooling — pin the version globally so upstream churn never surprises your scripts.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log
hsluv/hsluv
seampact/codegen
seampact/hooks
seampact/ir
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk