laravel/ranger
Ranger is a Laravel introspection library that walks your codebase and collects routes, models, enums, broadcast events, environment variables, and Inertia components. Register callbacks that fire as each item is discovered and receive a detailed DTO. Currently in beta.
Ranger is a read-only introspection layer: you resolve one Ranger instance, register callbacks for the components you care about, then call walk() once. Treat it as build-time tooling rather than request-time code.
composer require laravel/ranger
Because Ranger is still in beta, pin a known version in composer.json and watch the changelog before upgrading. The API is explicitly expected to change before v1.0.0.
Minimal first use case — dump every route URI and controller to understand an unfamiliar application:
use Illuminate\Support\Facades\Artisan;
use Laravel\Ranger\Components;
use Laravel\Ranger\Ranger;
Artisan::command('app:routes-inventory', function (Ranger $ranger) {
$ranger->onRoute(function (Components\Route $route) {
$this->line(sprintf(
'%-6s %-40s %s',
implode('|', $route->methods()),
$route->uri(),
$route->controller() ?? 'closure',
));
});
$ranger->walk();
});
Where to look first:
Laravel\Ranger\Ranger — the callback registration surface (onRoute, onModel, onEnum, onBroadcastEvent, plus the collection variants).Laravel\Ranger\Components\* — the DTOs. These are the real API you'll build against; inspect their methods before designing output.A good first production use is an internal contract report: route inventory, model/relationship map, enum values, Inertia page props, and env var names, emitted as JSON artifacts from CI.
Register everything, walk once. Ranger scans the application; don't call walk() per collector. Build up callbacks, collect into local arrays or DTOs, then emit in the collection callbacks.
$ranger = app(Ranger::class);
$routes = [];
$ranger->onRoute(function (Components\Route $route) use (&$routes) {
$routes[] = [
'uri' => $route->uri(),
'methods' => $route->methods(),
'controller' => $route->controller(),
'parameters' => $route->parameters(),
'validation' => $route->validationRules(),
'responses' => $route->responses(),
];
});
$ranger->onRoutes(function ($allRoutes) use (&$routes) {
file_put_contents(
storage_path('app/ranger/routes.json'),
json_encode($routes, JSON_PRETTY_PRINT)
);
});
$ranger->walk();
Generate frontend contracts from backend truth. The route, Inertia component, and enum collectors are the highest-leverage combination for Laravel + Inertia applications:
Use models for schema and relationship documentation. Model DTOs expose attributes, types, relationships, and file paths. This is useful for Mermaid ERDs, onboarding docs, and detecting relations that point at classes that no longer exist. Note that $hidden, $visible, and $appends are respected, so the output reflects serialization rather than raw database columns — which is usually what you want for API-facing docs.
Make it a diffable CI artifact. Run Ranger in a CI job, write deterministic JSON, commit or upload it, and diff against the previous run. That turns introspection into change detection: new routes without tests, removed enum cases, changed event payloads, or a dropped Inertia prop become reviewable. Sort collections before writing, because discovery order is not a contract.
Design intentional ignore markers before you need them. Ranger honors attributes implementing Laravel\Surveyor\Contracts\Ignored on models, enum cases, broadcast events/channels, and controller classes/actions. Use conditional markers for environment-specific or integration-specific declarations:
#[Ignore(unless: 'services.fake_source_provider')]
case GitFake = 'gitfake';
Conditions can be a config key, a [class, method] callable, or a bool. This lets the same cached analysis serve different environments while still excluding what should be excluded.
Integrate with existing tooling rather than replacing it. Keep Ranger output as an input to your OpenAPI generator, TypeScript generator, or documentation pipeline. It is an introspection source, not a runtime router or a substitute for feature tests.
walk() repeatedly in one process.Route::domain(...), an APP_URL base path, or a non-standard port, verify generated URIs rather than assuming they match production URLs.$hidden, $visible, and $appends affect model components. This prevents leaking hidden attributes, but it also means the introspection output may differ from getAttributes() on the class. Don't treat it as a raw schema dump.ShouldBroadcastNow. If your event inventory seems complete but a specific event is missing, check whether it implements ShouldBroadcast, ShouldBroadcastNow, or neither — and whether a marker is excluding it.onRoutes, onModels, etc. fire after discovery. Ordering-sensitive output belongs there.onRoutes or only onModels, dump() the DTO type and payload, then add collectors back. Most surprises are either an ignored declaration or an inference limitation, not a Ranger bug.How can I help you explore Laravel packages today?