spatie/laravel-web-tinker
Adds a browser route to your Laravel app for running Artisan tinker without the terminal. Includes light and dark modes, but executes arbitrary code, so use it only as a dev dependency and never in production or with real data.
Assessment stance: Trial — adopt as a developer-experience tool only, never as a runtime dependency.
spatie/laravel-web-tinker is a thin presentation layer over PsySH/Tinker that exposes an interactive REPL at a configurable route (/tinker by default). It is a single-purpose developer tool, not a product capability. The correct TPM framing is "does this measurably reduce engineering friction (debugging, data inspection, onboarding) relative to its security and governance cost?" — not "what feature does this unlock?"
Architecture fit
1.10.1 Laravel 12, 1.10.5 Laravel 13), so it is unlikely to be the constraint on framework upgrades.--dev Composer dependency by design, which is the right default. Enforcement of "dev-only" is a process problem, not a package problem.OutputModifier interface plus configurable middleware list are the only extension points; both are stable and small. Expect no deep customization — treat it as a fixed appliance.Integration feasibility
composer require --dev, php artisan web-tinker:install, optional config publish. Realistically under an hour including route verification and a security review.'enabled' => env('APP_ENV') === 'local' guard is the single most important line in the package. Any deviation from it is a deliberate security decision requiring a viewWebTinker Gate plus an explicit owner.Technical risk
APP_ENV, an accidentally committed config, a leaked preview URL, or a --no-dev-less production build yields remote code execution with application credentials, DB access, and any attached secrets. This is a critical-severity risk with a low-probability-but-plausible trigger.User::first() — lands in a browser and potentially in screen shares or recordings.1.9.1 (HTML injection prevention), 1.10.0 (client-side output purifying), 1.8.4 (output cleanup) show repeated hardening of the render path. Current version appears clean, but this class of bug recurs in tools that echo arbitrary PHP output into the DOM.Key questions
composer install --no-dev in the deploy image, route introspection test)?viewWebTinker Gate, and does it sit behind SSO/VPN rather than a public URL?docker exec php artisan tinker, Telescope, Debugbar, Clockwork, log-driven debugging), and what is the measured saving?Stack fit
web-tinker:install).psy/psysh and Laravel Tinker; it inherits the Tinker version already constrained by the framework, so it does not generally force dependency conflicts.public/vendor/web-tinker.Migration path
docker compose exec app php artisan tinker and dd()-driven debugging to a browser REPL.Compatibility
composer.json (--dev), not a floating constraint, so composer update on the dev toolchain does not silently change execution semantics.1.10.2 custom ExecutionLoopClosure, reverted in 1.10.3 to built-in Shell::execute(), refined in 1.10.4). Anything older than 1.10.4 should be treated as unsupported for containerized development.PSYSH_CONFIG/config_file rather than writing to ~/.config/psysh — the 1.4.2 fix exists precisely because that path is unwritable in containers.Sequencing
enabled guard and Gate requirement./tinker returns 404 outside local. Publish config into the repo so the enabled line is reviewable in PRs.composer remove and a config deletion.Maintenance
enabled expression intact, keeping the Gate correct, and re-reviewing after any environment-topology change (new preview environment, new public-facing staging URL). Assign this to a named owner in the platform team.Support
is not allowed filesystem errors, output formatting surprises. Each of these has a historical changelog entry, so the upgrade path resolves most tickets rather than documentation.enabled, or remove from the image), who to contact, and how to audit the route.Scaling
User::all() on a large table), plus connection-pool exhaustion if several people run heavy queries simultaneously against a shared staging database. This is a strong argument for local-only: never point it at a database whose capacity you share with production traffic.Failure modes
| Mode | Trigger | Impact | Mitigation |
|---|---|---|---|
| RCE exposure | enabled true outside local, or package in production image |
Critical | CI assertion, --no-dev deploy, route 404 test |
| Hanging requests | Containerized dev (pre-1.10.4) | Developer blocked | Pin ≥ 1.10.4 |
| Secret/customer data surfaced | Exploratory queries on non-local data | High (compliance) | Local-only policy; no staging DB |
| PsySH config unwritable | Container filesystem permissions | Tool unusable | PSYSH_CONFIG env instead of home dir |
| Session/auth bug | Middleware reordering (see 1.6.0) | Gate bypass | Keep default middleware stack, review overrides |
| Abandonment | Spatie stops compat PRs | Blocks framework upgrade | Pin version; drop package (low exit cost) |
Ramp-up
php artisan tinker already know the mental model. A five-minute walkthrough plus the runbook covers it.How can I help you explore Laravel packages today?