Laravel N+1 Query Problem: How to Spot and Solve It

The N+1 query problem is the most common performance issue in Laravel apps. Here's how to detect it with the query log, fix it with eager loading, and prevent it from coming back.

Richard GamoraRichard GamoraFullstack developer·4 min read
LaravelEloquentPerformance

The N+1 query problem is the most common performance issue I see in Laravel apps. It is so easy to introduce that even careful developers ship it. The fix is simple once you know what to look for, and the prevention is even simpler.

What N+1 actually means

If you fetch a list of N records and then call a relationship on each one, Laravel runs one query for the list plus N more queries — one per relationship lookup. That is N+1 queries instead of two. On a list of 100 items, you have just made 101 round trips to the database.

It usually shows up in Blade templates that loop over a collection and access $item->author->name or similar. The page works, the data is right, and the database is silently doing far more work than it should.

Spotting it in development

Use Laravel Debugbar or Telescope to count queries on each request. Anything over 20 queries on a normal page is a yellow flag. Anything over 50 is almost always N+1 hiding somewhere.

If you do not want to install a package, enable DB::enableQueryLog() at the top of a controller and dump DB::getQueryLog() at the end. The repeating, near-identical queries are the giveaway.

The fix: eager loading

Use ->with() to load relationships in one query. Replace Post::all() with Post::with('author', 'comments')->get() and the N+1 becomes a flat 1+M (M = the number of relationships eager-loaded), which scales properly.

For nested relationships, use dot notation: Post::with('comments.user'). And if you only need a count, eager-load with withCount() instead of pulling the full relationship.

Preventing regressions

Add Model::preventLazyLoading() in your AppServiceProvider for non-production environments. It throws an exception the moment a lazy load happens, catching N+1 issues before they reach production. It is the single most useful one-line change you can make to a Laravel codebase.

About the author

Richard Gamora

Richard Gamora

Fullstack developer based in the Philippines, working mostly with Laravel and Vue.js, with eight years of production experience across web and mobile.

me@richardgamora.comUpwork ↗

More on Laravel