# Automatically Eager Load Relationships

By Dipesh Khanal
Published: 2025-06-01
Updated: 2025-06-02
Canonical: https://laranepal.com/blog/automatically-eager-load-relationships

When working with **Eloquent in Laravel**, you'll often deal with relationships between models—like District belongs to a User, or States has many Districts.

How Laravel loads these relationships matters a lot for performance.

Let’s dive into the two types of loading:

1. **Lazy Loading**
2. **Eager Loading**

---

## Lazy Loading (Default)
[Lazy loading](https://laravel.com/docs/12.x/eloquent-relationships#eager-loading) means that Laravel delays loading the related data until you actually use it.

For Example:
```php
$users = \App\Models\User::all();

foreach ($users as $user) {
    echo $user->district->name;
}

```

This will:

Run `1 query` to get all users.

For each user, run another query to get its district.

Total queries: `1 (users) + N (districts)`
For 10 users, that’s 11 queries — this is the` N+1` problem.

Problem
As the number of records grows, this becomes slower and heavier on the database.

---

## Eager Loading
[Eager loading](https://laravel.com/docs/9.x/eloquent-relationships#lazy-eager-loading) tells Laravel to fetch the related data up front, in the same request.

For Example:
```php
$users = \App\Models\User::with(['district'])->get();

foreach ($users as $user) {
    echo $user->district->name;
}

```

This will:

Run `1 query` to get all posts.

Run `1 query` to get all users related to those posts.

Total queries: `2`
Much faster and more efficient.

---

### Multiple Relationships
You can eager load multiple relationships at once 
```php
$users = \App\Models\User::with(['district','posts'])->get();

```

---

### Nested Relationships
You can eager load nested relationships at once 
```php
$users = \App\Models\User::with(['district.state.country','posts'])->get();

```
---

# How We Manually Load Relationships in Laravel
Before Laravel 12.0.8, the standard way to deal with relationships was to manually specify them using `with()`.

Example:
```php
$users = \App\Models\User::with(['district.state.country','posts'])->get();

```

In this example:

We’re manually telling Laravel to load the district and posts relationships.

This avoids `N+1` problems.

This level of control is powerful but...

---
## The Problem With Manual Eager Loading

While eager loading is a great solution to the `N+1` problem, doing it manually comes with some pain points:

1. Repetition
You often repeat the same `with()` calls across multiple controllers, services, or queries.

2. Cognitive Load
You always need to remember which relationships are used in a view or response.

3. Prone to Bugs
Forgetting to eager load a relationship leads to unintentional `N+1` queries.

4. Tight Coupling to Usage
View or component logic often dictates which relationships should be loaded — not the model itself.

---

# Laravel 12.0.8 to the Rescue: Automatic Eager Loading
After this update, you can now use a config in `AppServiceProvider` and eager load all the relationships of any model. No need to use `with()` again and again.

Here's how
```php
<?php

namespace App\Providers;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        Model::automaticallyEagerLoadRelationships();
    }
}
```

Laravel automatically includes the district, posts relationships - no `with()`, no N+1 query problem.

Let's see with example.

```php
// web.php

<?php

use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    $users = \App\Models\User::all();
    return view('welcome',compact('users'));
});
```

```php
<?php

namespace App\Models;

use Database\Factories\UserFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    /** @use HasFactory<UserFactory> */
    use HasFactory, Notifiable;

    public function district(): BelongsTo
    {
        return $this->belongsTo(District::class, 'district_id');
    }
}

```
Similarly `District` belongs to `State` and `State` belongs to `Country`

here is the blade file.
```html
<!doctype html>
<html lang="en">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

    <title>Automatic Eager Loading</title>
</head>
<body>
<div class="container">
    <table class="table">
        <thead>
        <tr>
            <th scope="col">#</th>
            <th scope="col">Name</th>
            <th scope="col">Email</th>
            <th scope="col">Country</th>
            <th scope="col">State</th>
            <th scope="col">District</th>
        </tr>
        </thead>
        <tbody>
        @forelse($users as $user)
            <tr>
                <th scope="row">{{$loop->iteration}}</th>
                <td>{{$user->name}}</td>
                <td>{{$user->email}}</td>
                <td>{{$user->district->state->country->name}}</td>
                <td>{{$user->district->state->name}}</td>
                <td>{{$user->district->name}}</td>
            </tr>
        @empty
            <tr>
                <td colspan="6" class="text-center">No users found</td>
            </tr>
        @endforelse


        </tbody>
    </table>
</div>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
        crossorigin="anonymous"></script>
</body>
</html>
```

here we have listed all the users with state, district and country. Lets see the result without eager loading.

![Laravel Query With Lazy Loading](https://laranepal.com/storage/8ON3n3g8k4fmfFmnZ5SgOAyeQPAqT9PQKZxlo2w5.png)
In the above screenshot, we can see that it is taking ```302``` query to load all the data with lazy loading. Now let's enable the magic line of code. And this is the result after enabling it.
![Laravel Query With Eager Loading](https://laranepal.com/storage/SAbWWVZFb6qfFtxL8e2H536U1hWNXctD2Mwi2n5y.png)
Now the ```302``` query has vanished to only ```5``` queries. 

***Another Helpful Tip:*** 
Use another configuration on your ```AppServiceProvider``` to avoid Lazy Loading in your local development envirnoment.
```php
  Model::preventLazyLoading(!app()->isProduction());
```
---
## Conclusion

The new [automaticallyEagerLoadRelationships()](https://laravel.com/docs/12.x/eloquent-relationships#automatic-eager-loading) method in **Laravel 12.0.8** is a game-changer for optimizing performance and writing cleaner code.

By centralizing which relationships are eager loaded directly inside your models, you can:

1. Eliminate repetitive `with()` calls
2. Avoid the dreaded `N+1` query problem
3. Keep your controllers and services clean
4. Boost your app’s database performance effortlessly

And with the added ability to prevent lazy loading in non-production environments, Laravel now gives you everything you need to catch performance issues early — before they ever hit production.

This small addition makes a big impact in how we work with Eloquent relationships. Start using it in your projects today — and enjoy more performant, readable, and maintainable Laravel apps.

Happy Coding! 🚀
Follow for more Laravel tips and deep dives. 😊

---
