yiisoft/yii-debug
Yii Debug is a debugging extension for Yii applications that provides a toolbar and panels for logs, database queries, performance profiling, request data, and more, helping developers inspect and troubleshoot application behavior during development.
yiisoft/yii-debug is a development-only debug toolbar and request inspector for Yii 3 applications. It records each request, exposes a browsable /debug UI, and injects a toolbar into HTML responses.
Minimal setup:
composer require --dev yiisoft/yii-debug
In a standard Yii 3 app template, look first at:
config/packages/yiisoft/yii-debug/ — the packaged defaults (params, DI, routes)config/environments/dev/ — where debug is normally enabledvendor/yiisoft/yii-debug/src/Collector/ — the built-in collectors (request, DB, logs, events, router, timeline, services)vendor/yiisoft/yii-debug/src/Panel/ — how collected data is renderedruntime/debug/ — where request snapshots are stored by defaultEnsure the debug middleware is in the web middleware stack. It should sit near the top so it can wrap routing and the rest of the request lifecycle:
// config/web/di/application.php (illustrative)
use Yiisoft\Yii\Debug\DebuggerMiddleware;
return [
'middlewares' => [
ErrorCatcher::class,
DebuggerMiddleware::class, // early, before routing
Router::class,
// ...
],
];
Enable it through params (name and exact keys depend on your template version — verify against config/packages/yiisoft/yii-debug/params.php):
// config/common/params.php
'yiisoft/yii-debug' => [
'enabled' => true, // gate this on YII_DEBUG / dev env
'url' => '/debug',
'panels' => [
// Request, DB, Log, Event, Router, Timeline panels
],
'trackedServices' => [
// service id => collector config
],
],
First use case: load any HTML page, click the toolbar entry, and open the request detail. Start with the Request panel to confirm inputs/routing, then the Timeline panel to spot slow middleware or DB calls. For JSON/API responses where the toolbar is not injected, go directly to /debug and pick the request from history.
Environment-gated enablement. Treat debug as a dev dependency only. Wire enabled to YII_DEBUG or keep it exclusively in config/environments/dev/, and let production load no debug config at all. This avoids both the performance hit and accidental data exposure.
Middleware placement. DebuggerMiddleware should be one of the outermost middleware so it observes the full request/response cycle. If it ends up after routing, panels show incomplete data and the toolbar may be missing from responses.
Custom panels and collectors. The day-to-day extension pattern is: write a collector that gathers scalar data during the request, then a panel that renders it. Register the panel in the panels config. Keep collected payloads small and serializable — summaries and counts, not full objects.
final class MyCollector
{
private array $events = [];
public function collect(object $event): void
{
$this->events[] = ['name' => $event::class, 'at' => microtime(true)];
}
public function getCollected(): array
{
return $this->events;
}
}
Tracking services. Use trackedServices to have the DI container record construction and method calls for selected services. This is the fastest way to answer "why is this service created three times per request" without adding temporary logging.
DB and log panels. These only show meaningful data when the underlying package is instrumented: the DB panel relies on the DB package's profiling hooks, and the log panel needs the PSR-3 logger wired to the debug collector. If a panel is empty, check the dependency wiring before assuming the panel is broken.
Timeline markers. Wrap suspect code with the profiler begin/end calls used by the DB and timeline collectors. Custom markers show up in the Timeline panel and are often more useful than adding error_log() calls during a debugging session.
History-driven debugging. Because requests are persisted, the common workflow is: reproduce an issue, then open /debug, compare the failing request against a known-good one, and diff queries, timings, and log entries side by side.
Console runs. Debug data for CLI commands is collected separately from web requests. If a bug only appears in a console command, check the debug UI for the CLI snapshot rather than expecting it to appear among web requests.
API access. The debug UI exposes the stored snapshots, so you can fetch request detail as structured data for ad-hoc scripting or a smoke check, rather than scraping the HTML panel.
require-dev and dev-only config./debug directly for API work; don't expect the toolbar on an endpoint returning application/json.Content-Length. Content injection can interfere with streamed responses and precomputed content lengths. If a download or SSE endpoint misbehaves with debug on, suspect the middleware./debug itself works.runtime/debug/. Configure retention/history limits or prune periodically, and make sure the web user can write there. A full or unwritable runtime directory results in silently missing snapshots./debug will conflict. Change the debug url param or restrict the panel behind an IP allowlist middleware.trackedServices, clear the config cache — otherwise the old panel list is served and changes appear to have no effect.enabled => false (or omit the config) in test and CI environments to avoid overhead and snapshot noise.How can I help you explore Laravel packages today?