Skip to content

Eloquent Eager Loading — Solving the N+1 Problem in Laravel

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Eloquent Eager Loading. We cover key concepts, practical examples, and best practices to help you master this topic.

Laravel Eloquent eager loading prevents N+1 query problems by loading related models in advance with with(), load(), and loadMissing() methods.

What You'll Learn

By the end of this tutorial, you'll use with() to eager load relations, constrain eager loads, lazy eager load with load(), select specific columns, and prevent N+1 automatically.

Why Eager Loading Matters

N+1 queries are the most common performance problem in Laravel applications. Eager loading reduces database queries and eliminates performance degradation from loop-triggered Lazy Loading.

Real-World Use

A blog index page lists 50 posts with their authors and comment counts. Without eager loading, the page makes 1 + 50 + 50 = 101 queries. With eager loading, it makes 3 queries.

Eager Loading Path

flowchart LR
  A[Eloquent ORM] --> B[Eager Loading]
  B --> C[Pre-Load]
  B --> D[Lazy Load]
  B --> E[Constrained]
  B --> F[Forced Prevention]
  B --> G{You Are Here}
  style G fill:#f90,color:#fff

Basic Eager Loading

Load relationships upfront.

<?php
// Without eager loading (N+1 problem)
$posts = Post::all();                   // 1 query
foreach ($posts as $post) {
    echo $post->author->name;           // N queries
}
// With eager loading
$posts = Post::with("author")->get();   // 2 queries
foreach ($posts as $post) {
    echo $post->author->name;           // No additional queries
}
// Multiple relations
$posts = Post::with(["author", "comments", "tags"])->get();
// Nested relations
$posts = Post::with("author.profile", "comments.user")->get();

Lazy Eager Loading

Eager load relationships on existing models.

<?php
// After initial query
$posts = Post::all();
$posts->load("author");
$posts->load(["comments" => fn($q) => $q->where("approved", true)]);
$posts->loadMissing("author");
// Single model
$post = Post::first();
$post->load("author", "tags");
$post->loadCount("comments");

Constrained Eager Loading

Apply conditions to eager loaded relations.

<?php
use Illuminate\Database\Eloquent\Builder;
$users = User::with(["posts" => function (Builder $query) {
    $query->where("published", true)
          ->orderBy("created_at", "desc")
          ->limit(5);
}])->get();
// With column selection
$users = User::with(["posts:title,slug,created_at,user_id"])->get();
$users = User::with(["posts" => function (Builder $query) {
    $query->select("id", "title", "user_id", "created_at")
          ->where("published", true);
}])->get();

Eager Load Counts

Count relations without loading models.

<?php
$posts = Post::withCount("comments")->get();
foreach ($posts as $post) {
    echo $post->comments_count;
}
// Multiple counts
$posts = Post::withCount(["comments", "likes", "views"])
    ->withCount(["comments as approved_comments" => fn($q) => $q->where("approved", true)])
    ->get();
// Conditional counts
$posts = Post::withCount(["comments", "comments as pending_comments" => fn($q) => $q->where("status", "pending")])->get();

Preventing N+1 Automatically

Use N+1 detection packages or strict mode.

<?php
// In App\Providers\AppServiceProvider
use Illuminate\Database\Eloquent\Model;
public function boot(): void {
    Model::preventLazyLoading(!$this->app->isProduction());
    // Or always throw exceptions
    Model::preventLazyLoading(true);
}
// This throws an exception when lazy loading happens
// Comment out preventLazyLoading in production after optimization

Common Mistakes

1. Eager Loading Without Using the Relation

Loading a relation that is never accessed wastes resources.

2. Not Selecting Foreign Keys in Constrained Loads

When selecting specific columns, include the foreign key. Otherwise Eloquent cannot match related models.

3. Over-Eager Loading

Loading many relations in a single query creates large joins. Consider lazy eager loading for secondary relations.

4. Eager Loading Counts When Not Needed

withCount adds a subquery. Only load counts when using them.

5. Nested Eager Loading Without Constraints

Deep nested relations load everything. Use constraints to limit depth and size.

Practice Questions

1. What is the N+1 Problem?

Loading the parent model and then lazy loading a relation in a loop, causing N additional queries.

2. How does with() prevent N+1?

It loads all related models in one query and associates them in memory.

3. What is the difference between load() and loadMissing()?

load() always loads. loadMissing() only loads if not already loaded.

4. How do you count relations efficiently?

Use withCount() to add a count subquery without loading models.

5. Challenge: Optimize a query with constrained eager loading.

<?php
$articles = Article::with(["category", "comments" => function ($q) {
    $q->where("approved", true)->latest()->limit(5);
}])->withCount(["comments", "likes"])->latest()->paginate(20);

FAQ

Does eager loading always improve performance?

Usually yes. For simple one-to-one relations, lazy loading may be faster. Measure both.

Can I eager load nested relations?

Yes. Use dot notation: with('author.profile.settings').

What happens if I select specific columns without the foreign key?

Eloquent cannot match the related models. Always include foreign keys.

How do I eager load only one level of a nested relation?

Use constraint: with('comments' => fn($q) => $q->with('user')).

Can I mix with and withCount?

Yes. chain both methods on the same query.

Mini Project: Optimized Post Listing

Build an optimized post listing with proper eager loading.

<?php
class PostController {
    public function index(): View {
        $posts = Post::with(["author" => fn($q) => $q->select("id", "name", "avatar")])
            ->withCount(["comments", "likes"])
            ->with(["tags:name,slug"])
            ->published()
            ->latest()
            ->paginate(20);
        return view("posts.index", compact("posts"));
    }
}

What's Next

Eloquent Performance Eloquent Serialization Eloquent Query Scopes

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro