Preventing N+1 issues globally in Laravel using Auto Eager Loading
Eager loading in Laravel is a way to load related models when you query a model. This is done to prevent the N+1 problem, which occurs when you load a model and then load its related models one by one, resulting in multiple queries to the database.
This can be a performance issue, especially when you have many related models. Eager loading allows you to load all the related models in a single query, which can significantly improve performance.
For example, if you have a User
model that has many Post
models, you can eager load the posts like this:
$users = User::with('posts')->get();
foreach ($users as $user) {
// This will not run a separate query for each user
echo $user->posts->title;
}
This will load all the users and their posts in a single query, instead of loading each user’s posts one by one like so.
$users = User::all();
foreach ($users as $user) {
// This will run a separate query for each user
echo $user->posts->title;
}
This will result in an N+1 problem, where you will have one query to load all the users and then one query for each user to load their posts.
This is great but as you can tell, eager loading is not always the default behavior in Laravel. You have to explicitly tell Laravel to eager load the related models using the with()
method.
To fix this, Laravel now has a way to enable eager loading globally that will automatically eager load the related models for you.
Auto Eager Loading Globally
Laravel 12.x introduced (contributed by Serhii Litvinchuk) a new method called automaticallyEagerLoadRelationships()
on the Model
class. This method allows you to enable auto eager loading across all the models in your application.
Important: This feature is still in beta and the Laravel team is gathering community feedback on this. So, you may expect some changes in this functionality in the future.
You can enable this feature by adding the following code to your AppServiceProvider
:
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Model::automaticallyEagerLoadRelationships();
}
}
So, now, even the problematic code with N+1 issues, as I showed earlier, will work without any issues.
// Since auto eager loading is enabled globally,
// this will work without any N+1 issues
$users = User::all();
foreach ($users as $user) {
echo $user->posts->title;
}
Auto Eager Loading on Models
If you don’t want to enable auto eager loading globally, you can also enable it on a per-model basis. You can do this by adding the automaticallyEagerLoadRelationships()
method to your model like so.
use App\Models\User;
User::automaticallyEagerLoadRelationships();
Auto Eager Loading on Queries
And finally, you can also enable auto eager loading on a per-query basis. You can do this by using the withRelationshipAutoloading()
method like so.
$users = User::all()->withRelationshipAutoloading();
foreach ($users as $user) {
echo $user->posts->title;
}
In closing
I think this is a great feature to have in Laravel and potentially a lifesaver for newbies who are not familiar with eager loading.
You can read more about this feature in this PR.
Like this article?
Buy me a coffee👋 Hi there! I'm Amit. I write articles about all things web development. You can become a sponsor on my blog to help me continue my writing journey and get your brand in front of thousands of eyes.