Laravel detect N+1 queries before they reach production

~ 1 min read

Laravels Eloquent ORM is great for walking relationships and just getting the job done. But it comes at a price without planning each relationship walked can generate more queries against your database, while with a bit of upfront planning the child relationships can be fetched and hydrated into models in the same query as the parent resource. Which can drastically increase performance, and in the days of serverless/auto-scaling databases often charging by query volume also reduce costs.

So how do I detect where N+1 queries slipped through in development?

In your Laravel project open AppServiceProvider and add this code, which will make Laravel throw a Illuminate\Database\LazyLoadingViolationException every time a relationship is lazy loaded in non-production environments.

namespace App\Providers;
 
use Illuminate\Support\ServiceProvider;
 
class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        // ...
        
        Model::preventLazyLoading(! app()->isProduction());
        
        // ...
    }
}

How do you fix the queries? Use the with method with you Eloquent queries.

e.g. instead of

    $post = Post::find($id);
    echo $post->author->name;

preload the author with

    $post = Post::with('author')->find($id);
    echo $post->author->name;

all posts →