Eliminating the N+1 Problem in Laravel Applications
Understanding the N+1 Query Trap
The N+1 problem occurs when your application executes one query to fetch a parent record and then executes a separate query for every child record associated with it. In a application, this usually happens when you iterate over a collection of models and access a relationship that hasn't been loaded. For instance, fetching three products and then querying the database for each product's prices results in four total queries. While negligible at a small scale, this pattern scales poorly; a hundred products will trigger a hundred and one queries, drastically slowing down your application.
Prerequisites
To follow this guide, you should have a baseline understanding of and the framework. You should be familiar with relationships and how to define them within your models.
Key Libraries & Tools
- : A robust PHP framework providing the Eloquent ORM.
- : The database mapper used to interact with your data via PHP classes.
- DB Facade: A tool used here to enable query logging for performance monitoring.
Solving the Issue with Eager Loading
The most direct solution is using the with() method. This instructs to fetch all related records in a single additional query using a WHERE IN statement.
// Instead of lazy loading, we eager load the relationship
$products = Product::with('prices')->get();
If you find yourself always needing a relationship, you can automate this by adding the $with property to your model. This ensures the relationship is always present without manual intervention in your controllers.
class Product extends Model {
protected $with = ['prices', 'variants'];
}
Granular Control: Without and WithOnly
Sometimes, global eager loading is overkill. If you have the $with property set but want to exclude a specific relation for a single request, use the without() method. Conversely, withOnly() overrides the model's defaults entirely, ensuring you only pull exactly what you need for that specific execution context.
Enforcing Best Practices with PreventLazyLoading
introduced a powerful safety net: Model::preventLazyLoading(). By placing this in your AppServiceProvider, the framework will throw a LazyLoadingViolationException whenever you accidentally trigger an N+1 query.
public function boot()
{
Model::preventLazyLoading(! app()->isProduction());
}
This configuration is a developer's best friend. It forces you to write clean, eager-loaded code during development while ensuring your production environment remains stable for end users.
Syntax Notes & Tips
- Query Logging: Use
DB::enableQueryLog()andDB::getQueryLog()to verify exactly how many queries your code triggers. - Array Syntax: The
$withproperty and thewith()method both accept arrays, allowing you to load multiple relationships simultaneously. - Nested Loading: You can eager load nested relations using dot notation, such as
with('prices.currency').
- 44%· companies
- 33%· products
- 11%· products
- 11%· products

Dealing with the n+1 problem in Laravel
WatchLaravel // 5:47
The official YouTube channel of Laravel, the clean stack for Artisans and agents. We will update you on what's new in the world of Laravel, from the framework to our products Cloud, Forge, and Nightwatch.