beyondcode/laravel-query-detector
Detect N+1 query issues in Laravel during development. Monitors database queries in real time and alerts you when repeated queries suggest missing eager loading, helping you optimize performance and reduce unnecessary database calls.
Install the package in development mode:
composer require beyondcode/laravel-query-detector --dev
First use case: Enable it immediately in debug mode. No configuration needed—it automatically detects N+1 queries and shows browser alerts. Test by:
php artisan serve in debug mode (APP_DEBUG=true in .env).@foreach($posts as $post) {{ $post->author }} @endforeach).Key files to check:
config/querydetector.php (published via php artisan vendor:publish --provider="BeyondCode\QueryDetector\QueryDetectorServiceProvider").app/Providers/EventServiceProvider.php (for custom event listeners).Post::find(1)->author).config('querydetector.threshold') times (default: 1), it triggers.@foreach($posts as $post) {{ $post->comments }} @endforeach$posts = Post::with('comments')->get();with() on the parent query to load relations upfront.Configure config/querydetector.except to ignore specific relations:
'except' => [
Post::class => [
Comment::class,
'comments',
],
],
Use case: Exclude relations that are intentionally loaded lazily (e.g., for pagination).
Extend functionality by adding new output classes (e.g., Slack notifications):
// config/querydetector.php
'output' => [
\BeyondCode\QueryDetector\Outputs\Log::class,
\App\Outputs\SlackOutput::class, // Custom class
],
Listen for \BeyondCode\QueryDetector\Events\QueryDetected to trigger custom logic:
// app/Providers/EventServiceProvider.php
protected $listen = [
\BeyondCode\QueryDetector\Events\QueryDetected::class => [
\App\Listeners\LogToSentry::class,
],
];
Use the JSON output to embed warnings in API responses:
'output' => [
\BeyondCode\QueryDetector\Outputs\Json::class,
],
Example response:
{
"data": [...],
"meta": {
"warnings": [
{
"query": "SELECT * FROM `comments` WHERE `post_id` = ?",
"relation": "comments",
"model": "App\Models\Post",
"count": 5
}
]
}
}
Manually register the provider in bootstrap/app.php:
$app->register(\BeyondCode\QueryDetector\LumenQueryDetectorServiceProvider::class);
False Positives with Dynamic Queries
Post::where('id', $id)->first()->author as N+1 even if $id varies.'except' => [
Post::class => ['author'], // Ignore all author queries
],
Debugbar Conflicts
barryvdh/laravel-debugbar and fruitcake/laravel-debugbar, the package may fail to resolve the Debugbar facade.AppServiceProvider.Threshold Too Low
threshold: 0 will alert on every relation query, overwhelming output.threshold: 2 to catch only obvious inefficiencies.Lumen Compatibility
bootstrap/app.php for Lumen.Empty Queries
Post::find(1)->relation where the parent model doesn’t exist may trigger false alerts.empty_queries config (v2.0+) to ignore them:
'empty_queries' => true,
Inspect the Query Log Enable Laravel’s query log to correlate alerts with actual queries:
DB::enableQueryLog();
$posts = Post::all();
dd(DB::getQueryLog());
Check the Backtrace The alert includes a backtrace. Look for:
@foreach($posts as $post) {{ $post->author }} @endforeach$post->comments in loops.Test with Realistic Data Use seeders to populate test data that triggers N+1 (e.g., 10 posts with 5 comments each).
Disable for Production
Set QUERY_DETECTOR_ENABLED=false in .env to avoid runtime overhead in production.
Custom Output Classes
Extend \BeyondCode\QueryDetector\Outputs\OutputInterface to create new channels (e.g., Datadog, Sentry):
namespace App\Outputs;
use BeyondCode\QueryDetector\Outputs\OutputInterface;
class DatadogOutput implements OutputInterface {
public function output(array $queries) {
// Send to Datadog API
}
}
Modify the Threshold Dynamically Override the threshold per request:
config(['querydetector.threshold' => 3]); // For a specific route
Exclude Specific Routes Disable detection for non-critical routes (e.g., APIs):
if (request()->is('api/*')) {
config(['querydetector.enabled' => false]);
}
Integrate with CI/CD
Use the JSON output to fail builds with N+1 queries:
# In GitHub Actions
if grep -q '"warnings"' response.json; then
echo "N+1 queries detected!" >&2
exit 1
fi
How can I help you explore Laravel packages today?