Laravel Query Optimization with Eager Loading
When working with Laravel's Eloquent ORM, one of the most common performance killers is the N+1 query problem. It appears the moment you load a collection of models and then touch a relationship inside a loop.
The N+1 problem
$posts = Post::all(); // 1 query
foreach ($posts as $post) {
echo $post->author->name; // +1 query PER post
}
Load 50 posts and you fire 51 queries: one for the posts, plus one for every author. It is invisible in code review but deadly under load.
The fix: eager loading with with()
$posts = Post::with('author')->get(); // 2 queries total
foreach ($posts as $post) {
echo $post->author->name; // no extra queries
}
Laravel runs one query for posts and a single WHERE author_id IN (...) for all authors - 2 queries no matter how many posts.
Nested & multiple relationships
// Multiple relations
$posts = Post::with(['author', 'comments'])->get();
// Nested relations (dot notation)
$posts = Post::with('comments.user')->get();
// Constrain a relation with a closure
$posts = Post::with(['comments' => fn ($q) => $q->latest()->limit(5)])->get();
Load only the columns you need
$posts = Post::with('author:id,name')->get();
Selecting id,name keeps the payload small - just always include the foreign key (id) or the relation will not match.
Eager load after the fact
Already have the collection? Load relationships afterwards with load():
$posts = Post::all();
$posts->load('author');
Catch N+1 automatically
Enable strict mode in a service provider so lazy loading throws during development:
use Illuminate\Database\Eloquent\Model;
Model::preventLazyLoading(! app()->isProduction());
Key takeaways
with()eager-loads upfront (2 queries);load()eager-loads an existing collection.- Always eager-load any relationship you touch inside a loop.
- Use column selection and closures to load only what you need.
- Turn on
preventLazyLoadingin dev to catch N+1 before it ships.
Try the challenge
Practice what you just learned. Write your solution, reveal hints if you get stuck.
Instructions
The loop below reads $post->author inside each iteration, firing one extra query per post — the classic N+1 problem. Rewrite the query so the author relationship is eager-loaded, and the whole list runs in just 2 queries.
Starter code
$posts = Post::all();
foreach ($posts as $post) {
echo $post->author->name;
}
Your solution
$posts = Post::with('author')->get();
foreach ($posts as $post) {
echo $post->author->name;
}

