Laravel cookbook · Intermediate
Catch N+1 queries with strict Eloquent mode
Pages slow down as data grows because relations are lazy loaded in loops.
Approach
Turn on strict mode outside production so lazy loading, silently discarded attributes and missing attributes
throw. Fix the offenders with with(), withCount() and load().
Solution
<?php
// app/Providers/AppServiceProvider.php
namespace App\Providers;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
Model::shouldBeStrict(! $this->app->isProduction());
// In production, log lazy loading instead of throwing.
Model::handleLazyLoadingViolationUsing(function (Model $model, string $relation) {
logger()->warning('Lazy loaded relation', ['model' => $model::class, 'relation' => $relation]);
});
}
}
<?php
use App\Models\Post;
// Before: 1 query for posts + 1 per post for author + 1 per post for comment counts
// After: 3 queries total
$posts = Post::query()
->with(['author:id,name', 'tags'])
->withCount('comments')
->latest()
->paginate(20);
Pitfalls
- Enabling strict mode only in tests, so lazy loading in rarely tested pages slips through.
- Eager loading whole relations when only a count or a few columns are needed.
load()inside loops, which is the same N+1 problem.
Variations
Model::automaticallyEagerLoadRelationships()eager loads relations on first access for whole collections.- Laravel Debugbar or Telescope show query counts per request.
Further reading: Preventing lazy loading
Reference: https://laravel.com/docs/13.x/eloquent-relationships#preventing-lazy-loading
More Laravel recipes
- Authorize actions with policies
- Cache expensive data with stale-while-revalidate
- Call external APIs with timeouts, retries and fakes
- Delete old records automatically with prunable models
- Dispatch events and listeners after the transaction commits
- Issue scoped API tokens with Sanctum
- Make queued jobs reliable with retries, backoff and uniqueness
- Prevent race conditions with transactions and row locks