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.
Architecture fit
Ranger is not an application feature library; it is an introspection substrate. It walks the codebase via the Surveyor static analyzer, emits typed DTOs per discovered component (Components\Route, Model, Enum, BroadcastEvent), and gives you two hook points: per-item callbacks (onRoute, onModel) and per-collection callbacks (onRoutes(Collection)) fired once the walk completes. That two-tier design is the right shape for our purposes — per-item hooks for accumulating state, collection hooks for emitting a finished artifact.
Architecturally this means Ranger belongs at the build/CI boundary, not in the request path. The realistic product surfaces it unlocks are: generated OpenAPI/JSON:API schemas (it already collects validation rules, possible responses, API resource additional data, and $hidden/$visible/$appends), typed frontend contracts (Inertia component props and shared data), SDK/client generation, route+permission inventories for audit, and contract tests for the model graph. It is a generator's input, not a runtime dependency.
Fit is strong for conventional Laravel monoliths whose routes, models, enums, and events live in discoverable paths. Fit degrades sharply for apps using heavy metaprogramming, dynamic route registration, or package-provided routes outside scanned paths — Ranger's fidelity is bounded by static analysis, not runtime truth.
Integration feasibility
Low mechanical effort, moderate governance effort. Adoption is a require-dev plus ~20 lines of callback registration. There is no schema migration, no data model change, no runtime surface. The package is MIT, Laravel-org-maintained, has a test suite badge, changelog, and releases — this is the top-tier of the maturity signals available for a pre-1.0 package.
The real cost is in not trusting it blindly. DTOs are inferred, so every consumer must be explicit about the difference between "Ranger didn't find it" and "it doesn't exist." Budget a spike, not an integration project.
Technical risk
| Risk | Severity | Notes |
|---|---|---|
| Beta API churn | High | README states the API is "subject (and likely) to change prior to v1.0.0." DTO accessors are the contract we'd build against. |
| Static-analysis fidelity gaps | High | Dynamic registration, macros, container-resolved controllers, computed validation rules. Under-collection is silent. |
| Zero dependents | Medium | 68 stars, 0 dependents: no ecosystem battle-testing. We would be a reference implementation, absorbing discovery cost. |
| Behavioral drift between minors | Medium | v0.4.0 changed scanning strategy; v0.2.x shipped repeated semantic fixes (union enums, ShouldBroadcastNow, camelCase binding, integer IDs). Semantics are still settling. |
| Environment-dependent output | Medium | .env/APP_URL presence and base-path handling affect results; ignore-marker conditions are resolved at collect time. Same commit can yield different artifacts per environment. |
| Single-maintainer concentration | Low–Medium | One primary author, though under the Laravel org with external contributors. |
| Sensitive data in artifacts | Medium | Env var names, model attributes, and broadcast payloads flow into DTOs. $hidden/$visible and ignore markers are honored — a good signal — but artifacts must still be treated as sensitive. |
Key questions
Route::resource, custom macros, conditionally loaded route files, package routes)? Is there a "skipped" signal, or only absence?Stack fit
Strong fit if the target app is Laravel 11–13 with conventional app/, routes/, config/ layout and source present at build time. Inertia and broadcast collectors are opt-in by relevance — if we don't use Inertia, those collectors are dead weight we simply never hook. Route, model, and enum collectors are the near-universal core and should drive the first deliverable.
Explicit non-fit: production container images that strip source (common with optimized builds). Ranger cannot run there. This reinforces the build-time-only decision.
Migration path
Greenfield — there is no incumbent to migrate from, only incumbents to reconcile with. Treat php artisan route:list --json, reflection-based model inspection, and any hand-maintained API docs as the baseline to diff against, not to replace on day one.
Compatibility
0.5.*), not a caret range, in require-dev.Insights\Collector) that exposes our own serializers rather than Ranger DTOs. Consumers depend on our JSON shape, not the beta API. This converts a Ranger breaking change from an app-wide incident into a single-file change.route:list + reflection if Ranger is abandoned.Sequencing
walk() against the largest app; dump every collection to JSON; measure wall time and peak memory; produce a route parity report against route:list (routes found / routes registered). This single number is the go/no-go gate — set an explicit threshold (e.g., ≥95% and every miss individually explained) before committing.Total realistic path to a first shipped artifact: 3–4 weeks including the spike.
Maintenance
Recurring cost is upgrade cycles, not code. The changelog shows a fast pre-1.0 cadence with behavioral fixes as often as features — that means each minor deserves a read, not just a version bump. Budget roughly one engineer-day per minor for triage, plus the snapshot-diff review. Post-1.0 this should drop substantially; until then, treat Ranger as a tracked dependency with an owner, not a set-and-forget dev dependency.
Support
No SLA. Laravel-org backing gives durability and roadmap alignment (Laravel 13 support landed early), but edge-case handling has historically been community-discovered — union enums, ShouldBroadcastNow, camelCase binding keys, integer-vs-string IDs all arrived as external PRs. Expect to file issues for our own edge cases and to carry a workaround in the adapter in the interim. That's acceptable for a build-time tool; it would not be for a runtime one.
Scaling
Cost scales with parsed file count. v0.4.0's "stop rescanning per collector" change materially improved this, but a full walk on a large monorepo is still a parse-everything operation. Mitigations: scope scans to app/, routes/, config/; run on a dedicated CI runner rather than alongside tests; cache/restore the analysis artifact if Surveyor supports it (open question 2); shard per-application in a monorepo. Memory is the more likely ceiling than wall time — assert a budget and fail the job if exceeded rather than letting it silently degrade CI.
Failure modes
route:list and a diff-based alert when route/model counts drop unexpectedly between builds..env/APP_URL or flip-flopping ignore-marker conditions produce different artifacts from the same commit. Mitigate by pinning the environment used for artifact generation and recording it in the artifact metadata.$hidden/$visible/$appends and ignore markers are respected, which is a meaningful safeguard, but classify artifacts and restrict distribution as if unsanitized.Ramp-up
Low for the mechanics, moderate for the semantics. Any Laravel developer can register callbacks in an afternoon. The real learning curve is understanding what the DTOs mean — what "possible responses" actually captures, how validation rules are inferred, what a dropped relation implies. That knowledge is undocumented beyond the README and must be captured internally as the spike's primary deliverable. Estimate one engineer to competence in about a week, and require that the inference limits be written down and surfaced to every downstream consumer — otherwise teams will treat generated artifacts as authoritative and ship incorrect contracts.
How can I help you explore Laravel packages today?