Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Tinker Server Laravel Package

beyondcode/laravel-tinker-server

Run Laravel Tinker commands on remote servers through a simple HTTP endpoint. Tinker Server exposes an authorized route so you can execute PHP and inspect your app from anywhere, ideal for serverless and Vapor deployments where SSH access isn't available.

View on GitHub
Deep Wiki
Context7

Getting Started

Verify compatibility before you type a single command. This package's last release was 2019-02-14 and the repo is archived. Its constraints pin against the PHP 7.x / Laravel 5.x era, so on PHP 8.1+ or Laravel 9+ expect composer require to fail resolution outright. Check composer.json on the tag you intend to install and compare against your php and laravel/framework versions first — the install is either trivial or impossible, and there is no middle ground where you get upstream help.

Install as a dev dependency only:

composer require --dev beyondcode/laravel-tinker-server

Auto-discovery handles the service provider on Laravel 5.5+. Publish the config so you can see the host/port the listener binds to:

php artisan vendor:publish --provider="BeyondCode\TinkerServer\TinkerServerServiceProvider"

The two-pane loop is the whole product. Terminal one, from the project root:

php artisan tinker-server

Terminal two, hit your app — a route, a test, an Artisan command — with a ts() call dropped into the code path:

$user = User::with('orders')->find(42);

ts($user);

return view('users.show', compact('user'));

Back in terminal one, $user is a live variable in a PsySH session. $user->orders->count(), $user->toArray(), $user->orders->first()->status — all interactive, without halting the request the way dd() would.

First use case to try: the "why is this collection empty / why is this attribute wrong" bug. Put ts($query->toSql()) and ts($query->getBindings()) next to each other, let the request finish, and interrogate both in the REPL rather than editing, re-running, and re-dumping. If that loop doesn't feel faster than your current dd() habit within ten minutes, stop — the rest of this package is variations on it.

Implementation Patterns

Replace dd() at the end of a chain, not the middle. The package's value is that the request keeps running. So the idiomatic move is to ts() a value and let the response render normally, rather than killing the request to inspect. Reach for dd() when you genuinely want to stop; reach for ts() when you want to keep going and inspect afterwards.

Forward several named values in one pass. Batch the things you'll want to compare in the REPL instead of one round-trip per hypothesis:

ts($user);
ts($user->orders);
ts($user->orders->pluck('status')->unique());
ts(config('services.stripe'));

Each arrives as a variable you can cross-reference ($user->orders->count() against the plucked set) — that cross-referencing is the actual ergonomic win over a wall of dump() output.

Use it in queues and Artisan commands, not just HTTP. A long-running worker or a php artisan invocation has the same problem — you can't dd() a job without killing the worker. ts($payload) inside handle() forwards the value over the socket and the job keeps processing. Same for seeders, import commands, and scheduled tasks. This is where the package most clearly beats dd().

Pair it with PsySH's own tooling. Once you have $model, use ls $model, doc $model->save, and show $model to explore the class rather than dumping attributesToArray(). The REPL is the same one behind php artisan tinker, so any muscle memory transfers.

Treat ts() like a breakpoint, not a log line. Add it, learn what you needed, delete it before committing. If you find yourself wanting to keep a ts() call, that's a signal the real answer is a test assertion or a log entry. A codebase with ts() calls sprinkled through it is a codebase whose authors stopped cleaning up.

Use it alongside — not instead of — a maintained tool. Telescope or Clockwork for request-level inspection, Ray for the ergonomic dump()-replacement, Xdebug for stepping. ts() occupies a narrow slot: interactive post-hoc drilling into a specific value. Don't try to make it carry the whole debugging workflow.

Gotchas and Tips

Assume incompatibility until proven otherwise. Archived repo, seven-year-old release, zero dependents, no CVE process. If it doesn't resolve on your stack, the honest question isn't "how do I force it" — it's "do we fork and repin, and who owns that?" That's a build decision, and it should be made deliberately, not discovered halfway through a sprint.

Serialization is a semantic trap, not a crash. Values cross a process boundary. Closures, resources, PDO connections, and some Eloquent graphs will fail or degrade; object identity is lost; and mutations you make in the REPL do not write back to the live application. If you read this as a live debugger rather than a snapshot viewer, you will confidently misdiagnose your own app. Nothing about that failure looks like an error message.

Keep the listener on loopback, always. A process that receives values and evaluates PHP inside a bootstrapped application is a shell. Dev .env files routinely carry staging and production credentials, so never bind to 0.0.0.0, never run it on a shared host, and never forward the port out of a container. This is a policy decision, not a per-developer preference.

Containers and remote workspaces are where it quietly dies. Sail, devcontainers, Codespaces — the socket transport crosses a boundary that isn't designed for it. If you're containerized, budget the port-forwarding work explicitly or skip the package; the friction will eat the ergonomics.

First-run "nothing happens" is almost always the server. If ts() silently no-ops or throws a socket error, check that php artisan tinker-server is actually running in the other pane and that the port in config/tinker-server.php matches what's listening. Confirm with php artisan tinker-server --help and a netstat/lsof check rather than re-reading your application code.

Port collisions are common. The default port is a fixed number; if something else on your machine holds it, the server starts dirty or fails quietly. Pick a less-contended port in the config and note it in your team's onboarding doc.

Removal must be mechanical and boring. composer remove --dev beyondcode/laravel-tinker-server, grep for ts(, delete. If that grep returns hits in code that's already committed, you've confirmed the discipline problem — fix it before it spreads. The fact that cleanup is this cheap is the package's best remaining property.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons