Laravel Stats for Laravel and Lumen Code Inventories
📈 Get insights about your Laravel or Lumen Project
At a glance
- What is it?
- Laravel Stats is a Composer package that classifies application classes and reports their distribution through Artisan. It is useful for maintainers who want a repeatable view of controllers, models, jobs, tests, and custom components.
- Who is it for?
- Adopt Laravel Stats if you maintain a Laravel or Lumen application and need a repeatable inventory of its PHP classes, especially when planning refactoring or reviewing component boundaries. Do not use it as a complete code-quality report or as a replacement for runtime monitoring.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 86 days ago.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Laravel Stats inventories
Laravel Stats addresses a practical maintenance problem: an application can contain many PHP classes without an obvious, current answer to how many controllers, models, commands, jobs, listeners, notifications, or tests it has. The package scans application source and groups classes into Laravel-specific components. It is aimed at developers who want to inspect that structure from the command line, including maintainers working across a Laravel or Lumen project. It also supports project-specific components through custom classifiers.
The inventory is classification based, not a general-purpose source-code analysis report. The README says the package scans files in the paths defined in the configuration file and applies Classifiers to determine which Laravel component each class represents. A class therefore needs to satisfy the relevant inheritance, interface, trait, or registration rule. A file existing on disk does not guarantee that it will be counted in the expected category.
This distinction matters when interpreting the result. Laravel Stats can tell you how classes are grouped according to its detection rules. It does not state that a controller is well designed, that a model has no defects, or that a test suite provides useful coverage. Those judgements require other tools and project-specific review.
How Laravel Stats classifies PHP classes
The documented mechanism is a two-stage process. First, the package scans the files listed under `paths`. Second, built-in Classifiers inspect the resulting classes and decide whether they belong to a recognized component. The report therefore depends on both filesystem scope and the classification rules implemented by the package.
Several rules are based on inheritance. A Controller, for example, must be registered with a Route and must not extend `Livewire\Component`. Models must extend `Illuminate\Database\Eloquent\Model`, Commands must extend `Illuminate\Console\Command`, and Requests must extend `Illuminate\Foundation\Http\FormRequest`. Mail classes extend `Illuminate\Mail\Mailable`, while Notifications extend `Illuminate\Notifications\Notification`. Migrations and seeders have their own Laravel base classes.
Other categories depend on application registration or traits. Policies must be registered in the `AuthServiceProvider`, middleware must be registered in the HTTP kernel, and event listeners must be registered for an Event in the `EventServiceProvider`. Events must use the `Illuminate\Foundation\Events\Dispatchable` trait, while Jobs must use `Illuminate\Foundation\Bus\Dispatchable`. This approach is precise for applications that follow conventional Laravel registration patterns, but it can expose mismatches between a class and the way the application is wired.
The package also recognizes Livewire components, Nova resources, actions, dashboards, filters, and lenses, plus Blade components, custom casts, factories, and several test types. The supported categories are broad, but they are not unlimited. A project-specific abstraction needs a custom classifier before it can appear as its own component.
Installing Laravel Stats and generating the first report
The README gives Composer as the normal installation path. The package is installed as a development dependency and registers itself automatically. The first report is generated with the `stats` Artisan command. The documentation specifically warns that `php artisan config:clear` should be run before generating statistics.
Install the package with this command:
composer require "wnx/laravel-stats" --devAfter installation, clear the application configuration before asking the package to inspect the project:
php artisan config:clearThen generate the standard statistics report:
php artisan statsThe README does not define a required database table, queue worker, or external service for this command. That makes the initial use relatively direct for a Laravel application that already has its project files in place. The package still depends on the application having the paths and registrations that its classifiers expect.
If a custom configuration file is needed, the documented publishing command is:
php artisan vendor:publish --provider="Wnx\LaravelStats\StatsServiceProvider"The README describes this step as optional. Publishing the file is relevant when the default paths or custom classifier configuration need to be adjusted; otherwise, automatic registration is the simpler documented path.
Reading standard, JSON, and verbose output
Laravel Stats provides a normal Artisan report and a JSON format. JSON is useful when the inventory needs to be consumed by another local process or retained for a project-specific comparison. The README does not document a persistent database, dashboard, or hosted reporting service, so the command should not be treated as an automatic analytics platform.
Generate JSON output with:
php artisan stats --jsonFor a report that includes the classes grouped into each component, use verbose mode:
php artisan stats --verboseThe same detail is available when JSON is requested:
php artisan stats --json --verboseThe verbose option is relevant when a count does not match what a maintainer expects. Instead of only showing a total, it can show the class names assigned to a component. That gives the operator a starting point for checking whether a registration was missed, whether a class uses an unexpected inheritance structure, or whether the configured paths do not include the intended directory.
The package also excludes Pest PHP test files automatically. According to the README, Pest tests cannot currently be detected because of how Laravel Stats works internally. This is a documented boundary, not a claim that Pest tests should be counted as PHPUnit tests. Projects using Pest should account for this difference when interpreting test counts.
Adding an application-specific classifier
The built-in component list does not cover every application abstraction. Laravel Stats addresses this through the `Classifier` contract and the `stats.custom_component_classifier` configuration array. A custom classifier supplies a display name, decides whether a reflected class satisfies the component definition, and states whether it contributes to application-code and test counts.
The README's example uses a repository abstraction. Its classifier checks whether the class is a subclass of `App\Repositories\BaseRepository`, names the category `Repositories`, returns true for application code, and returns false for tests:
// app/Classifiers/RepositoryClassifier.php
<?php
namespace App\Classifiers;
use Wnx\LaravelStats\ReflectionClass;
use Wnx\LaravelStats\Contracts\Classifier;
class RepositoryClassifier implements Classifier
{
public function name(): string
{
return 'Repositories';
}
public function satisfies(ReflectionClass $class): bool
{
return $class->isSubclassOf(\App\Repositories\BaseRepository::class);
}
public function countsTowardsApplicationCode(): bool
{
return true;
}
public function countsTowardsTests(): bool
{
return false;
}
}Register it in the package configuration:
// config/stats.php
<?php
...
'custom_component_classifier' => [
\App\Classifiers\RepositoryClassifier::class
],
...This extension point is useful for architectures with repositories, domain services, modules, or other first-party concepts. It also creates a maintenance obligation. The classifier must stay synchronized with inheritance changes, namespace changes, and naming conventions in the application.
Limits, alternatives, and maintenance costs
The clearest limitation is that Laravel Stats reports what its classifiers can recognize, not whether the application is healthy. It can miss or misclassify code that uses unconventional registration, indirect inheritance, dynamic wiring, or a structure outside the documented rules. Pest test files are explicitly excluded because they cannot currently be detected. The README also does not document rollback behavior for generated output, a historical database of reports, or comparisons between runs, so those capabilities should not be assumed.
PHPUnit is a real alternative for a different purpose. Laravel Stats can be run with `./vendor/bin/phpunit` as part of the package's own development workflow, but PHPUnit executes tests and reports test results. Laravel Stats inventories application classes and groups them into components. PHPUnit is appropriate when the question is whether tests pass; Laravel Stats is appropriate when the question is which Laravel components exist and how they are grouped. Neither tool replaces the other.
Maintenance status is recent but not a guarantee of compatibility with every future Laravel release. The repository is not archived, and the last push was on 2026-07-29. Recent releases include v2.20.0 on 2026-07-29, v2.19.0 on 2026-03-12, and v2.18.0 on 2025-11-24. That history indicates continued release activity, while the README's SemVer policy leaves upgrade planning tied to release tags. The package is licensed under the MIT License. That is a permissive licensing choice, but application owners still need to review the license file and their own compliance obligations rather than treating this summary as legal advice.
For local development of the package itself, the README documents a Composer path repository with a symlink option. That approach is for testing an unpublished local copy, not for installing the package in a normal application.
Editorial conclusion
Adopt Laravel Stats if you maintain a Laravel or Lumen application and need a repeatable inventory of its PHP classes, especially when planning refactoring or reviewing component boundaries. Do not use it as a complete code-quality report or as a replacement for runtime monitoring. Verify first that your configured paths, framework registrations, and custom classifiers match the structure of your application, then confirm whether the JSON output meets your reporting needs.
Frequently asked questions
How do I install Laravel Stats in a Laravel or Lumen project?
Install it with `composer require "wnx/laravel-stats" --dev`. The package registers itself automatically, and the README also documents an optional Artisan command for publishing its configuration file.
How do I generate Laravel Stats output?
Run `php artisan config:clear` first, then run `php artisan stats`. The package also supports `php artisan stats --json`, `--verbose`, and the combination `php artisan stats --json --verbose`.
Does Laravel Stats count Pest PHP tests?
No. The README says Pest PHP test files are automatically excluded and that Pest tests cannot currently be detected by Laravel Stats. This limitation is documented in the project's discussion #194.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/stefanzweifel-laravel-stats)Was this useful?