Eager Loading and Query Optimization in Laravel

Laravel is one of the most popular PHP frameworks because of its clean syntax and powerful features. One of the important parts of working with Laravel is understanding how to optimize database queries. When working with Eloquent ORM, it is very common to run into performance issues due to something called the N plus 1 query problem. In this post, we will learn how to solve this problem using eager loading and other query optimization techniques.
What is the N plus 1 Query Problem
Let us say you have two models: Post and Comment. Each Post has many Comments. If you write code like this:
$posts = Post::all();
foreach ($posts as $post) {
echo $post->comments->count();
}
This code will run one query to get all posts. Then for each post, it will run another query to get its comments. If there are 100 posts, it will run 1 plus 100 queries. This is the N plus 1 problem.
How to Solve It with Eager Loading
Laravel gives us a simple solution to this. It is called eager loading. You can use the with method to load related data in one go:
$posts = Post::with('comments')->get();
foreach ($posts as $post) {
echo $post->comments->count();
}
Now Laravel will run only two queries. One to get all posts, and one to get all comments that belong to those posts. This is much faster and more efficient.
Nested Eager Loading
You can also load deeper relationships. For example, if a Comment belongs to a User, and you want to get the user of each comment, you can do:
$posts = Post::with('comments.user')->get();
This will load posts, their comments, and the users who made those comments.
Eager Loading Specific Columns
Sometimes you do not need all the columns. You can optimize the query even more by selecting only the needed fields:
$posts = Post::with(['comments' => function ($query) {
$query->select('id', 'post_id', 'content');
}])->get();
This helps reduce the amount of data loaded into memory.
Using Lazy Eager Loading
Laravel also allows you to load relationships after the main query is executed. This is called lazy eager loading:
$posts = Post::all();
$posts->load('comments');
It is useful when you do not know which relationships to load until after fetching the main data.
Avoiding Unnecessary Relationships
Do not eager load everything by default. Only load what you actually need. Loading many relationships when you do not use them can hurt performance.
Using Count Instead of Full Relationship
If you only need to count related models, do not load the full relation. Use withCount instead:
$posts = Post::withCount('comments')->get();
foreach ($posts as $post) {
echo $post->comments_count;
}
This will generate a simple SQL count and will be much faster than loading all comment data.
Chunking Results
When working with large datasets, you should not use get. Instead, use chunk to process data in smaller parts:
Post::with('comments')->chunk(100, function ($posts) {
foreach ($posts as $post) {
// process post and comments
}
});
This saves memory and avoids timeouts.
Query Logging and Debugging
Use Laravel debug tools like debugbar or log queries manually to find performance issues:
DB::listen(function ($query) {
logger($query->sql);
});
You can see how many queries are being run and what they are.
Summary
Eager loading is a powerful feature of Laravel Eloquent that helps you avoid the N plus 1 query problem. By loading related data efficiently, you can greatly improve the performance of your application.
Always check what relationships you need, use withCount for simple counts, avoid loading unnecessary data, and use chunking for big datasets.
If you understand and apply these techniques, your Laravel apps will be faster and more scalable.
Thanks for reading. Let me know if you want more posts on Laravel performance tips.
Subscribe to my newsletter
Read articles from Rameez Karamat Bhatti directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Rameez Karamat Bhatti
Rameez Karamat Bhatti
I am a full-stack developer currently working with PHP, Laravel, Tailwind CSS, and Livewire. I also work extensively with Inertia.js to build seamless single-page applications using Vue.js and Laravel. I have experience building reactive frontends with Vue.js and React, and robust backends with REST APIs. I am highly proficient in MySQL, MongoDB, and also comfortable working with PostgreSQL for relational data projects. My focus is on clean, scalable code and building user-focused digital products.