Home › Gaze › Debug Laravel without dd()

Debug Laravel without dd()

dd() is the fastest way to see a value in Laravel, and the fastest way to break the page you are looking at. Here is where it gets in the way, what Laravel already gives you instead, and how to send your dumps to a window of their own while the app keeps running.

Start with how to find and fix N+1 queries in Laravel, the most common reason a Laravel page slows down as your data grows.

Where dd() and dump() get in the way

  • JSON APIs. dump() writes HTML into the response, so the client gets a page of markup instead of the JSON it expects. dd() stops the request before your response is sent at all.
  • Redirects. A dump() before return redirect() lands in a response the browser never shows, because it follows the redirect straight away.
  • Jobs, commands and tests. There is no browser. A dump goes to the queue worker's console or the test output, if you happen to be watching it.
  • Loops. dd() stops at the first item, and dump() in a loop of five hundred prints five hundred trees on one page.

What Laravel gives you instead

Logs

A log line works everywhere, production included, and never touches the response:

use Illuminate\Support\Facades\Log;

Log::debug('Order totals', ['order' => $order->id, 'total' => $total]);

You then read storage/logs/laravel.log, or follow it live with php artisan pail on apps that have Laravel Pail installed. Logs are text, though: a nested model turns into one long line, and you dig your entry out from everything else.

Telescope

Laravel Telescope records requests, queries, jobs and more in a dashboard, and its dump watcher records dump() output there while the Telescope dumps screen is open in your browser. It is a full install with its own database tables, and you switch between your app and the dashboard.

A window for your dumps

Gaze is a desktop app built for this. Swap dd() for gaze() and the value appears in the Gaze window with the file and line it came from, while the request carries on and the page, the JSON or the redirect stays exactly as it was. Calls from jobs, commands and tests land there too, grouped by whatever ran them.

With gaze-laravel installedgaze($order);                      // instead of dump($order)
gaze($order)->label('order');      // with a label you can search for
gaze()->table($rows, 'Rows');      // rows as a table
gaze_dd($payload);                 // send it, then stop, like dd()
gaze()->pause();                   // wait on this line until you press Continue
The Gaze window: a Laravel request with its queries grouped under it, and a dumped Order model open in the inspector with its attributes
A dumped Eloquent model in Gaze, under the request that sent it, with the file and line one click from your editor.

A forgotten call does nothing in production: gaze() becomes a no-op and gaze_dd() does not stop the script. Before you deploy, php artisan gaze:clean removes leftover calls anyway.

Dumping inside loops and long jobs

In a loop, update one entry instead of adding hundreds. Calling send() again on the same instance replaces its content:

$progress = gaze('Importing');
foreach ($batches as $i => $batch) {
    import($batch);
    $progress->send("Imported batch {$i}");   // updates the same entry
}

On collections and query builders, ->gaze() passes the value through, so you can look at it in the middle of a chain without breaking it:

collect($rows)->gaze('rows')->map(...);       // a collection, mid-chain
User::where('active', true)->gaze()->get();   // the SQL with bindings, before it runs

Seeing the same query over and over while you do this? That is probably an N+1: how to find and fix N+1 queries in Laravel. For a query that is simply slow, see how to find slow and duplicate queries.

Questions

What is the difference between dd() and dump() in Laravel?

dump() prints a value and lets the code carry on; dd() prints it and stops the request, the way die() would. Both write into the response, which is why they get in the way in APIs and redirects.

How do I see dump() output from a queued job?

A job runs in the queue worker, so dump() writes to that worker's console. Log the value with Log::debug, or send it to a desktop window like Gaze, where it appears under the job that ran it.

Is it safe to leave gaze() calls in my code?

Gaze is off in production: gaze() becomes a no-op and gaze_dd() does not stop the script. Before you deploy, php artisan gaze:clean removes leftover calls anyway.

When can I use Gaze?

Gaze is free and coming soon for Mac, Windows and Linux. Get launch news from the Gaze page and we will email you the day it is out.

Sources: Laravel: Logging · Laravel: Tailing logs with Pail · Laravel: Telescope dump watcher

Keep the page. See the value.

Gaze is a desktop debugger for PHP, Laravel and JavaScript. Every dump, query, log and exception lands in one window, grouped by the request that caused it, with N+1 and slow queries flagged for you. It is free and coming soon for Mac, Windows and Linux. Get launch news and we will email you the day it is out.

Get launch news See Gaze, the free desktop debugger for Laravel