Your Laravel app looks great locally, but once you put it online with real data, page loads crawl to a halt. The culprit is often a silent performance killer known as the N+1 query problem.

An N+1 query happens when your code runs one query to get a list of items, and then runs a brand new query for every single item to fetch its related data.

  • What an N+1 query actually is under the hood
  • How to spot N+1 queries in your Laravel application
  • How to fix the problem using Laravel's eager loading
  • How to test your fixes so they stick

Understanding the Problem

Imagine you want to display a list of ten blog posts and the name of the author for each post. If you write your code naively, Laravel will first run one query to grab all ten posts. Then, it runs ten separate queries to find the author for each individual post.

That is one query for the posts, plus ten queries for the authors. In database terms, that equals eleven queries total, or N+1 queries where N is the number of posts.

The Solution: Eager Loading

Laravel provides a built-in feature called eager loading to solve this exact problem. Instead of asking the database for related data one by one, you tell Laravel to grab all the related data upfront in a single extra query.

Here is how you write a normal lazy-loaded query that causes the N+1 problem in your controller:

$posts = Post::all();

foreach ($posts as $post) {
    echo $post->user->name;
}

This code triggers one query for the posts and N queries for the users. The key takeaway is that accessing relationships inside a loop without preparation creates a massive performance bottleneck.

Vue.js development Photo by James Harrison on Unsplash

How to Fix It With With

To fix this, we use the with method to load the relationship ahead of time. Eager loading reduces your total database trips down to just two queries, no matter how many posts you have.

$posts = Post::with('user')->get();

foreach ($posts as $post) {
    echo $post->user->name;
}

By adding with('user'), Laravel fetches all the required users in one neat batch query. The key takeaway is that eager loading turns dozens of database calls into just two predictable queries.

Common mistakes

A common mistake is forgetting to use eager loading when passing data into JavaScript frameworks like Vue.js via API resources. Another mistake is using eager loading everywhere 'just in case', which can fetch data you do not actually need and waste memory. Always check your app with a tool like Laravel Debugbar to see exactly how many queries your pages are running.

Open up an existing Laravel project today, install Laravel Debugbar, and check one of your index pages for hidden N+1 queries.