This page covers the Laravel side of the dumpio/client package. Read the PHP library page first for the basics (dio(), Dumpio::dump(), typed helpers) — everything there works in Laravel too. Here we add what Laravel makes automatic.
The big win in Laravel: automatic capture. With one env line you can stream every SQL query, every reported exception, every outgoing email, queued job, Livewire interaction, and more into Dumpio — without touching your application code.
Setup
The service provider is auto-discovered — you don't register anything. Just require the package:
1composer require --dev dumpio/client
Then, in your .env, turn Dumpio on for local development:
1DUMPIO_ENABLED=true
That's the minimum. Now dio(), Dumpio::dump(), and all the helpers send to the viewer. Automatic capture is opt-in — see below.
Is it on? The two switches
Dumpio must be enabled before anything is sent, and each capture is a separate switch on top of that.
DUMPIO_ENABLEDis the master switch. If you don't set it, it falls back toAPP_DEBUG. So it's on in local dev and off in production automatically — a normal production deploy sends nothing and registers no listeners.- Everything under "automatic capture" (queries, exceptions, mail, …) is off by default even when Dumpio is enabled. You turn each one on individually.
If nothing appears, the first thing to check is
DUMPIO_ENABLED=true(orAPP_DEBUG=true) and that the Dumpio app is running.
The config file
You can drive everything from .env, but if you want to see or change defaults, publish the config:
1php artisan vendor:publish --tag=dumpio-config
config/dumpio.php:
1return [ 2 'host' => env('DUMPIO_HOST', 'localhost'), 3 'port' => (int) env('DUMPIO_PORT', 21234), 4 'token' => env('DUMPIO_TOKEN', ''), 5 'enabled' => env('DUMPIO_ENABLED', env('APP_DEBUG', false)), // off in prod 6 7 'listen_queries' => env('DUMPIO_LISTEN_QUERIES', false), 8 'listen_exceptions' => env('DUMPIO_LISTEN_EXCEPTIONS', false), 9 'intercept_dumps' => env('DUMPIO_INTERCEPT_DUMPS', false),10 'listen_models' => env('DUMPIO_LISTEN_MODELS', false),11 'listen_cache' => env('DUMPIO_LISTEN_CACHE', false),12 'listen_jobs' => env('DUMPIO_LISTEN_JOBS', false),13 'listen_events' => env('DUMPIO_LISTEN_EVENTS', false),14 'listen_mail' => env('DUMPIO_LISTEN_MAIL', false),15 'intercept_mail' => env('DUMPIO_INTERCEPT_MAIL', false),16 'listen_http_client' => env('DUMPIO_LISTEN_HTTP_CLIENT', false),17 'listen_livewire' => env('DUMPIO_LISTEN_LIVEWIRE', false),18 'listen_livewire_verbose' => env('DUMPIO_LISTEN_LIVEWIRE_VERBOSE', false),19 'register_macros' => env('DUMPIO_REGISTER_MACROS', true),20 'stamp_requests' => env('DUMPIO_STAMP_REQUESTS', true),21];
Automatic capture
Each switch below is off by default. Flip the env var (or the config key) to forward that signal — no code changes needed.
| Env var | What it forwards | Dump type / channel |
|---|---|---|
DUMPIO_LISTEN_QUERIES |
Every executed SQL query (via DB::listen), with bindings and time |
query |
DUMPIO_LISTEN_EXCEPTIONS |
Reported exceptions, with request/user context | exception |
DUMPIO_INTERCEPT_DUMPS |
The framework's dump() / dd() routed into the viewer |
var (dump) |
DUMPIO_LISTEN_MODELS |
Eloquent created / updated / deleted / restored |
model (models) |
DUMPIO_LISTEN_CACHE |
Cache hit / missed / written / forgotten |
event (cache) |
DUMPIO_LISTEN_JOBS |
Queue job processing / processed / failed |
event (jobs) |
DUMPIO_LISTEN_EVENTS |
Your application (non-framework) events | event (events) |
DUMPIO_LISTEN_MAIL |
Every outgoing email, as a rendered preview | mail (mail) |
DUMPIO_INTERCEPT_MAIL |
With LISTEN_MAIL: also cancel the real send (dev only) |
— |
DUMPIO_LISTEN_HTTP_CLIENT |
Outgoing Http:: requests, with status and timing |
http |
DUMPIO_LISTEN_LIVEWIRE |
Livewire component lifecycle (see below) | event (livewire) |
DUMPIO_LISTEN_LIVEWIRE_VERBOSE |
The high-volume Livewire points (boot/hydrate/dehydrate/destroy) — opt-in on top of LISTEN_LIVEWIRE |
event (livewire) |
A typical local setup:
1DUMPIO_ENABLED=true2DUMPIO_LISTEN_QUERIES=true3DUMPIO_LISTEN_EXCEPTIONS=true4DUMPIO_INTERCEPT_DUMPS=true
Queries
DUMPIO_LISTEN_QUERIES=true forwards every executed query as a query dump — the SQL, the bound parameters, the connection, and how many milliseconds it took. This is the easiest way to spot N+1 problems: load a page and watch the query list fill up — and with request correlation on (the default), the viewer flags the request with an amber N+1 ×N badge when the same query repeats.
Exceptions
DUMPIO_LISTEN_EXCEPTIONS=true forwards reported exceptions as exception dumps with a parsed stack trace and the current request/user context, so you can inspect a failure without digging through laravel.log. (See the app's Exceptions page for how they render.)
dump() / dd() interception
DUMPIO_INTERCEPT_DUMPS=true reroutes Laravel's own dump() and dd() into Dumpio (via VarDumper::setHandler) instead of rendering them inline. Your existing dd() calls now land in the viewer — and dd() still stops the request as usual.
Models, cache, jobs, events
These forward framework lifecycle signals as model or event dumps, each on its own channel (models, cache, jobs, events) so you can filter them. DUMPIO_LISTEN_EVENTS deliberately filters out framework-internal events to avoid a firehose.
Mail capture and the Mailpit-style trap
DUMPIO_LISTEN_MAIL=true hooks Laravel's MessageSending event and sends every outgoing email to the viewer as a mail dump — a full preview with rendered HTML, the text part, and the subject/from/to/attachments envelope, shown in a sandboxed iframe.
Add DUMPIO_INTERCEPT_MAIL=true and the listener also cancels the real send — a dev-only trap (like Mailpit/Mailtrap) so your test emails land only in Dumpio and never reach a real inbox. It requires listen_mail.
1DUMPIO_LISTEN_MAIL=true2DUMPIO_INTERCEPT_MAIL=true # don't actually send while developing
Outgoing HTTP-client calls
DUMPIO_LISTEN_HTTP_CLIENT=true forwards every outgoing request made with Laravel's Http:: client as an http dump with status and timing, via a global Guzzle middleware. Requires guzzlehttp/guzzle (which Laravel already uses). Great for seeing what a third-party API actually returned.
Livewire
DUMPIO_LISTEN_LIVEWIRE=true streams the lifecycle of your Livewire components to the viewer, so you can see a whole round-trip — what mounted, which action ran, which property changed, and what re-rendered — without echoing anything into the Blade markup. It requires livewire/livewire and works with Livewire 3 and 4 (a single hook covers both).
Each step becomes an event dump on the livewire channel (filter to #livewire to watch just these):
| Event | When it fires | Livewire | Payload |
|---|---|---|---|
livewire.mount |
A component mounts | v3 + v4 | the mount parameter names |
livewire.action |
An action method is called | v3 + v4 | the method name and its parameters |
livewire.update |
A property is updated (data binding) | v3 + v4 | the property path and its new value |
livewire.render |
The component re-renders | v3 + v4 | the view name |
livewire.island |
An island (partial) re-renders | v4 only | the island name |
Component exceptions are forwarded as full exception dumps on the same livewire channel (on both v3 and v4), so a failing update shows its stack trace instead of a silent 500.
Livewire 3 and 4. You don't configure anything version-specific. The integration registers a single Livewire componentHook(), whose API is identical across both majors, so one code path serves v3 and v4 alike. On both versions you get mount, action, update, render, and forwarded exceptions; livewire.island is emitted only on Livewire 4, where islands (partial re-renders) exist — on v3 that hook is simply never called, so nothing is emitted and nothing breaks. The hook is registered automatically whenever livewire/livewire is installed; if Livewire is absent, the feature is completely inert.
1DUMPIO_ENABLED=true2DUMPIO_LISTEN_LIVEWIRE=true
Then interact with a Livewire component and watch the #livewire channel: you'll see the mount, each action, the property updates it triggered, and the render — in order.
Verbose lifecycle points (opt-in)
The default capture stops at the events above. If you also need the low-level lifecycle — for example to inspect the state serialized to and from the wire — enable the verbose tier. These points fire on nearly every request for every component, so they sit behind a separate switch to keep the default stream readable. All four exist on both Livewire 3 and 4:
| Event | When it fires | Livewire | Payload |
|---|---|---|---|
livewire.boot |
The component boots (every request) | v3 + v4 | the component name |
livewire.hydrate |
State is restored from the wire (every request) | v3 + v4 | the component name |
livewire.dehydrate |
State is serialized back to the wire (every request) | v3 + v4 | the component name |
livewire.destroy |
The component is destroyed | v3 + v4 | the component name |
Turn it on alongside the standard capture:
1DUMPIO_LISTEN_LIVEWIRE=true2DUMPIO_LISTEN_LIVEWIRE_VERBOSE=true
or at runtime with Dumpio::showLivewireVerbose() / Dumpio::stopShowingLivewireVerbose(). The four verbose events land on the same #livewire channel with a gray flag, so they filter and search alongside the rest.
Turning capture on and off at runtime
The env flags only seed the initial state. Any capture can be flipped at runtime — handy inside a test, a Tinker session, or around one suspect block:
1Dumpio::showQueries(); // start forwarding queries now2$report->build(); // …the code you want to inspect…3Dumpio::stopShowingQueries(); // and stop4 5Dumpio::showAll(); // everything on6Dumpio::stopShowingAll(); // everything off
There's a show…() / stopShowing…() pair for Queries, Exceptions, Dumps, Models, Cache, Jobs, Events, Mail, HttpClient, Livewire, and LivewireVerbose. The generic form is Dumpio::enableFeature('queries') / disableFeature('queries').
The facade
The provider registers a Dumpio facade alias, so you can use it without importing the class:
1use Dumpio\Laravel\Facades\Dumpio;2 3Dumpio::query($sql, $bindings, $timeMs);4Dumpio::dump($user, 'user');
This is equivalent to \Dumpio\Dumpio::… or the global helpers (dumpio(), dio(), dumpio_query(), …).
Chainable macros: ->dio() and ->ddio()
The provider registers ->dio() and ->ddio() macros on query builders and collections (on by default; disable with DUMPIO_REGISTER_MACROS=false). They let you drop a dump mid-chain without breaking it — the dump ships the current state and returns $this:
1User::query()2 ->where('active', true)3 ->dio() // → query dump (SQL + bindings so far)4 ->whereDate('created_at', today())5 ->dio() // → query dump (with the extra clause)6 ->get();7 8collect($users)->dio('after filter'); // → var dump, returns the collection
->ddio() is the dump-and-die variant. The macros work on Eloquent\Builder, Query\Builder (DB::table(...)), and Support\Collection.
Send logs to the viewer (Monolog)
Point a log channel at Dumpio\Log\DumpioHandler to stream application logs into Dumpio as log dumps (the level picks the color):
1// config/logging.php2'channels' => [3 'dumpio' => [4 'driver' => 'monolog',5 'handler' => \Dumpio\Log\DumpioHandler::class,6 ],7],
Then log to it directly — Log::channel('dumpio')->warning('Auth failed', ['ip' => $ip]) — or add 'dumpio' to a stack channel's channels list to mirror your default log into the viewer. The handler never throws back into the logging pipeline.
Request correlation
Every dump emitted during one HTTP request automatically shares a requestId and
a requestLabel ("METHOD /path"), so the viewer can group them under a
collapsible request header — you see "what happened in this request" at a glance.
This is on by default; a global middleware opens a scope on request start and
closes it on terminate. Console commands and queued jobs have no request, so
their dumps stay ungrouped.
Turn it off with stamp_requests (DUMPIO_STAMP_REQUESTS=false). You can also
open a scope by hand — handy in a test or a long CLI job:
1Dumpio::beginRequest('import users'); // returns the id; label is optional2// … dumps here share the correlation …3Dumpio::endRequest();
Production safety
Leaving the package installed in production is safe: with enabled following APP_DEBUG, a production deploy configures the client as disabled and registers no listeners — a complete no-op. If you ever enable Dumpio on a shared or staging environment, gate individual dumps with ->when(...) so they only fire when you intend.