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

Tinker Laravel Package

laravel/tinker

Laravel Tinker is a powerful REPL for the Laravel framework, letting you interact with your entire application from the command line—evaluate PHP, run queries, and test code in a live environment via Artisan.

View on GitHub
Deep Wiki
Context7

Getting Started

Tinker is almost certainly already installed — it ships in require-dev of the Laravel skeleton — so the first step is usually just opening the shell:

php artisan tinker

You get a PsySH prompt (>) with your entire application bootstrapped: the container, Eloquent, facades, config, and every registered service provider. A good first session:

> app()->version()
> App\Models\User::count()
> $u = App\Models\User::with('posts')->first()
> $u->toArray()
> DB::table('users')->latest()->limit(5)->get()

Note that App\Models\User resolved without a use statement — Tinker's ClassAliasAutoloader registers your config/app.php aliases (and vendor aliases) so classes are reachable by short name. The second thing to try is the non-interactive mode, which is where most day-to-day automation lives:

php artisan tinker --execute="echo App\Models\User::count();"

Where to look first when something is unclear:

  • Laravel docs → Artisan Console → Tinker (the README defers to it entirely; there is no package-local documentation).
  • Laravel\Tinker\Console\TinkerCommand for the real option surface (--execute, --include) and the artisan-command confirmation logic.
  • Laravel\Tinker\ClassAliasAutoloader when an alias resolution surprises you.
  • The changelog for version gates: v3.x requires PHP 8.1+ and targets Laravel 13; v2.11.x is the branch for older PHP/Laravel combos, and several behaviours (--execute output, exit codes, model hidden/appended attributes, custom casters) only exist above specific minor versions.

First productive use case: use it as a data-inspection tool instead of writing throwaway routes or dd() calls. Pull a model, inspect hidden/appended attributes and relations, run the query you were about to put in a controller, and confirm it behaves before writing the code.

Implementation Patterns

Interactive exploration. The highest-value pattern is question → query → answer without touching the codebase:

> $u = App\Models\User::find(1)
> $u->load('orders.items')
> $u->orders->sum('total')
> App\Models\User::whereNull('email_verified_at')->count()
> App\Models\Order::where('status','pending')->toSql()

Because it is the real container, anything you can app() is available: app(ReportBuilder::class)->build(), Mail::fake(), event(new OrderShipped($order)), dispatch(new SyncJob()), Http::get(...)->json(). It is also a fast scratchpad for Str::, Arr::, Carbon, and validation rules.

Non-interactive one-liners (--execute). Since v2.2.0 this is the scriptable path, and it is genuinely useful for smoke checks and deploy tasks:

php artisan tinker --execute="echo Cache::get('build-id');"
php artisan tinker --execute="dump(App\Models\User::first()->only(['id','email']));"

Use single quotes around the PHP so your shell doesn't eat $variables. From v2.7.3 the output is raw (no PsySH decoration), so it pipes cleanly; from v3.0.0 exceptions produce a non-zero exit code, which means you can gate shell/CI logic on it. Version 2.4.1 fixed the loader leaking past --execute, so scripts that run repeatedly in one process are safe on current releases.

Preloading with --include. Put reusable helpers or fixture setup in a PHP file and bootstrap the session with it: php artisan tinker --include=dev/tinker-bootstrap.php. This is cleaner than pasting ten lines every morning.

Transaction-scoped experiments. There is no undo. When you're about to mutate data, open a transaction first and roll back explicitly at the end of the experiment:

> DB::beginTransaction()
> $u = App\Models\User::first(); $u->name = 'Test'; $u->save()
> DB::rollBack()

Or wrap the whole experiment in DB::transaction(function () { ... }). Better still, point the shell at a scratch connection/database before you start typing writes.

Query and N+1 debugging. DB::enableQueryLog() … DB::getQueryLog() inside the shell gives you the SQL and bindings for the exact snippet you're prototyping — often faster than wiring up Telescope for a one-off question. ->dd() on a query builder dumps SQL + bindings and halts.

Custom casters for domain objects. Tinker ships casters for HtmlString (v2.1.0), Stringable (v2.6.0), and ProcessResult (v2.8.1), and shows model hidden/appended attributes (v2.6.1). For your own value objects, custom caster support landed in v2.6.2 — define a class with PsySH's static cast* methods and register it on the shell (the wiring point is TinkerCommand::getCasters(); override it in a subclass if your version's config hook isn't available). This turns dump() output from a wall of private properties into something readable, which matters when a money/address/state object is what you inspect all day.

Team/onboarding usage. Because it boots the real app, php artisan tinker --execute="..." is a neat way to verify a deployed environment without SSH-ing into code: check a config value, confirm a queue connection responds, confirm a scheduled command's query returns rows.

Gotchas and Tips

  • It's a dev dependency — treat it that way. laravel/tinker lives in require-dev. Running composer install --no-dev in production removes it, and any deploy script relying on artisan tinker --execute will break. If you do keep it around, remember --execute bypasses the interactive confirmation guards you'd get at the prompt.
  • State does not survive the session. Variables, use imports, and DB::enableQueryLog() are per-process. Only readline history persists (~/.config/psysh/psysh_history on modern PsySH). That history file is a real secret-leak vector: tokens, passwords, and copied API keys typed into the shell end up in plaintext there.
  • There is no rollback safety net by default. User::truncate() is instant and permanent. Always confirm which .env/database you're attached to — config('database.default') and config('database.connections.mysql.database') — before destructive commands, and prefer DB::beginTransaction().
  • env() can return null in Tinker. After php artisan config:cache, the .env file isn't loaded, so env('FOO') is empty while config('services.foo') works. Always read settings via config() in the shell.
  • Alias collisions. Auto-registered aliases can clash with a use statement: use App\Models\User; is fine, but importing a class under a name that's already aliased can throw a "name is already in use" error mid-session. Fall back to the FQCN, or start a fresh session.
  • dd() kills the shell; dump() doesn't. Use dump() + exit only when you mean it. Related: Ctrl+C often just abandons the input line rather than cancelling a long-running query, so a runaway User::all()->each(...) will hold the terminal. Use lazy(), chunk(), or limit() — dumping a 50k-row collection is the most common way to make Tinker appear to hang.
  • --execute quoting bugs are shell bugs, not PHP bugs. Wrap the code in single quotes, avoid heredocs in Makefiles without care, and prefer echo/print for scalars and dump() for structures, since raw output means there's no automatic result echo.
  • Artisan commands run inside the shell are gated. Tinker prompts for confirmation before running most artisan commands from the prompt, with a whitelist for safe ones (e.g. migrate, migrate:install, optimize, clear-compiled, up/down). Don't expect a non-interactive --execute script to sail through Artisan::call('migrate:fresh') — use real artisan commands in deploy scripts instead.
  • PsySH trust prompts. Newer PsySH versions ask you to trust a project's local config; Tinker explicitly suppresses that prompt (v2.11.1 / v3.0.0). If you see trust prompts, you're on an older Tinker/PsySH pairing — upgrade rather than accepting blindly.
  • Version-pin deliberately. v3.x drops PHP 7.x/8.0 and targets Laravel 13; if you're on Laravel 9–12, stay on the 2.x line and pick a recent 2.11.x (PHP 8.5 and Symfony 8 compatible). Also keep an eye on the minimum psy/psysh constraint if you pin that separately.
  • Extension points worth knowing: TinkerCommand (options, confirmation logic, casters) and ClassAliasAutoloader (alias map) are the two classes you subclass or read when you need behaviour beyond the defaults. Everything else in the package is a thin adapter over PsySH.
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.
vento/laravel-airbrake
wfeller/laravel-batch
maco-studios/mage-os-installer
busarm/armie
siberfx/laravel-logger
kfteam1991/dcat-admin
dashed/dashed-laposta
dashed/dashed-ecommerce-montaportal
dashed/dashed-ecommerce-etsy
neohq/string-blade-compiler
log1x/acf-composer
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core
nodisrupt/laravel-agent
sierratecnologia/media-manager