spatie/laravel-ray
Send debug output from any Laravel app to Ray, Spatie's desktop debugging tool. Inspect HTML, arrays, queries, and Markdown, measure performance, and pause execution—all with the familiar dump-style workflow.
Architecture fit: spatie/laravel-ray is a development-time instrument, not a runtime component. It is a thin Laravel service provider plus a set of macros (query builder, test response, mailables, HTTP client, views, jobs) that serialize payloads and POST them to a local HTTP listener on localhost:23517 owned by the Ray desktop application. Architecturally this is a non-invasive, opt-in side channel: it registers watchers for exceptions, queries, mail, jobs, and cache/view events, and exposes global helpers (ray(), rd()) that no-op when disabled. It fits cleanly into a Laravel codebase precisely because it can be excluded from the production dependency graph via require-dev, which is the single most important architectural decision a TPM should enforce.
Integration feasibility: High on the PHP side, low on the organizational side. Composer install, auto-discovery, optional config publish (ray:publish-config), and env-var driven settings (RAY_HOST, RAY_PORT, enable flags) mean a single developer can be productive in under an hour. The friction is that the package is functionally inert without the Ray desktop client, which is a separate proprietary, commercially licensed product (free trial limited to 20 messages per session). The MIT license on this repository does not extend to the client. That is a procurement, not engineering, dependency.
Technical risk:
--no-dev not used, or an over-broad require), ray() calls become outbound HTTP attempts to a nonexistent host — latency, log noise, and a data-egress question if RAY_HOST is ever misconfigured to a remote address.localhost inside a Docker/Sail/DDEV container is not the host machine; RAY_HOST must be set per environment, and this is a recurring onboarding failure mode.register() made declarative, setProjectName() moved to boot()). It tracks framework releases promptly but is not a stable-ABI dependency.Key questions:
dump()-loop latency, this is the right tool.RAY_HOST configuration today?Stack fit: Laravel-first, PHP-first, and deliberately narrow. Requirements are a supported Laravel major (currently up through Laravel 13 per 1.43.6) and a compatible PHP runtime (PHP 8.5 deprecations addressed in 1.41.0 and 1.43.8). Octane compatibility has existed since 1.17.2, which matters for teams on long-lived workers. It does not serve non-PHP services, so it cannot be a standard across a polyglot stack — the sibling spatie/ray and JS packages would be separate adoptions.
Migration path: Additive, not substitutive. Install with composer require --dev spatie/laravel-ray, publish config if non-default host/port or project naming is needed, keep ray() calls inside the existing debug workflow alongside dump()/dd()/Telescope. There is no data migration, no schema change, no API contract change, and no runtime path alteration when disabled. The realistic "migration" is cultural: developers replacing dd()-and-refresh loops and tail -f storage/logs/laravel.log with payload inspection.
Compatibility: Watch three surfaces. (1) Composer constraint resolution against the app's Laravel/PHP matrix — pin a minor and let Renovate/Dependabot handle bumps, since minor releases here are frequently framework-version catch-ups. (2) CI — the package must be absent or explicitly disabled in pipelines; --no-dev installs in deploy and CI images are the primary control. (3) Container networking — RAY_HOST must be documented per dev topology (host.docker.internal, DDEV hostname, etc.).
Sequencing:
require-dev enforcement in review checklist, a lint rule or grep gate in CI for ray(/rd(/dump( in application code, and a documented RAY_ENABLED=false default for any shared environment.composer remove.Maintenance: Low and asymmetric. In production, zero — nothing ships if --no-dev is used. In development, the maintenance burden is routine dependency bumps with occasional framework-major catch-up releases; the package has historically lagged a Laravel major by weeks, not quarters, but the PHP 8.5 boot regression in 1.43.8 shows that minor bumps can break app boot. Budget for treating this as a pinned, Dependabot-managed dev dependency rather than a floating ^1.0.
Support: Two-tier. The package itself gets community/Spatie OSS support through GitHub issues under an MIT license with no SLA. The actual user-facing product — the Ray client — requires a commercial relationship, and the debugging workflow degrades to a 20-message trial without it. Escalation paths, refund terms, and seat management are vendor-negotiation items a TPM must own, not delegate to the team.
Scaling: Scales per developer, not per service. Each engineer runs their own client and their own local listener; there is no shared server, no aggregation, and no multi-tenant story. This is a feature (no infrastructure to run, no data leaving the laptop under default config) and a limitation (no team-wide shared debugging session, no historical record of debug payloads). If the org wants shared debugging context, this is not the tool. Also note the container topology cost scales with environment diversity — every new dev image variant is a new RAY_HOST configuration to document.
Failure modes:
ray()-heavy code paths; verify behavior on the pinned version rather than assuming.localhost:23517 and swallowed errors on every instrumented path. Control is deploy-time (--no-dev) plus a CI assertion.RAY_HOST in containers: silent loss of payloads; developers conclude "the package is broken."Ramp-up: Very low for any PHP developer already fluent in dump() — the mental model is identical, the syntax is ray() instead of dump(). Expect under a day to first productive use, with the main onboarding friction being the client install/license and the RAY_HOST step in containerized setups. Documentation is hosted externally at myray.app rather than in-repo, which is fine but means the internal runbook should capture the version-specific env matrix and the security posture (what data leaves the process, and to where) so developers don't have to infer it.
How can I help you explore Laravel packages today?