Create AWESOME code snippets and share them with the world in seconds!

X

Automatically Eager Load Relationships

Published on June 2, 2025 by

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 means that Laravel delays loading the related data until you actually use it.

For Example:

$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 tells Laravel to fetch the related data up front, in the same request.

For Example:

$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

$users = \App\Models\User::with(['district','posts'])->get();

Nested Relationships

You can eager load nested relationships at once

$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:

$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
 
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.

// web.php
 
<?php
 
use Illuminate\Support\Facades\Route;
 
Route::get('/', function () {
$users = \App\Models\User::all();
return view('welcome',compact('users'));
});
<?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.

<!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/[email protected]/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/[email protected]/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 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 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.

Model::preventLazyLoading(!app()->isProduction());

Conclusion

The new automaticallyEagerLoadRelationships() 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. 😊


 Dipesh Khanal

Laravel developer with a passion for clean code, open source, and helping others grow — one line at a time.

Filed in:

Discussion

Login or register to comment or ask questions

No comments or questions yet...

SPONSORED
Codesnap

Codesnap

Create AWESOME code snippets and share them with the world in seconds!