# Should I enable Model::preventLazyLoading only locally or in production too?

> Run it fully strict and throwing in local and CI; in production keep it on but wire handleLazyLoadingViolationUsing to log without failing the request.

- Asked: 2026-07-04
- Answered: 2026-07-07
- Asked by: Ayşe
- Tags: laravel, eloquent, performans
- Source: https://muhammetsafak.com/just-ask/should-i-enable-model-preventlazyloading-only-locally-or-in-production-too/
- Language: en-US
- Author: Muhammet Şafak

---
**Question:** I'm building an API with Laravel 11 and I want to catch N+1 queries before they reach a release. `Model::preventLazyLoading()` looks like the right tool, but I can't decide exactly where to enable it.

My worry is this: if I turn it on in production, I'm scared it will throw a fatal error (500) at a real user on some code path my tests missed. Should I only enable it locally, or is there a safe way to run it in production too?


Short answer: run it fully strict (throw) in local and CI; keep it on in production, but wire it to a handler that logs instead of throwing.

## Short answer

Your worry is valid — flipping raw throwing on cold in prod turns a latent bug into an instant outage. The trap here is treating this as a binary "local or prod" switch. The version that actually pays off is the same setting behaving differently per environment — loud where a developer can fix it, quiet where a real user would otherwise eat a 500. The underlying problem this setting catches — when eager loading is actually needed — is something I walked through in [the Eloquent relationships post](/blog/eloquent-relationships-hasmany-belongsto-and-eager-loading/).

## Why

1. **The setting can throw on a real user request.** `Model::preventLazyLoading()` throws a `LazyLoadingViolationException` on any lazy-load attempt. Great in development; catastrophic if it returns a 500 to a real user on a path your tests never exercised.
2. **It's one of three strict settings.** It's bundled with `preventSilentlyDiscardingAttributes` and `preventAccessingMissingAttributes` under `Model::shouldBeStrict()`. `shouldBeStrict()` turns all three on at once; enable them deliberately, not blindly. The other two are lower-risk in production, but `preventLazyLoading` is the one that can throw on a real user request, so it earns the separate handler treatment.
3. **It only catches lazy loads, not every N+1.** A query running inside a loop that isn't a relation lazy-load won't trip this mechanism. So you still need Telescope/Clockwork or query-count assertions in your tests.

## What to do

1. **Gate it by environment.** In `AppServiceProvider::boot()`, call `Model::preventLazyLoading(! $this->app->isProduction())`. That makes it strict everywhere except production, where throwing stays off.
2. **In production, log via a handler instead of throwing.** Use `Model::handleLazyLoadingViolationUsing(...)` to report the violation to Sentry/logs with the model + relation name, without crashing the request. You still see the N+1 in production telemetry, but you don't punish the user.

   ```php
   // app/Providers/AppServiceProvider.php
   public function boot(): void
   {
       Model::preventLazyLoading(! $this->app->isProduction());

       Model::handleLazyLoadingViolationUsing(function ($model, $relation) {
           report(new \RuntimeException(
               "Lazy loading detected: ".$model::class."::".$relation
           ));
           // no throw — the request continues its normal flow
       });
   }
   ```

3. **Roll it out gradually.** Keep production in log-only mode for a few weeks before switching to throwing; promote to throw only after the telemetry is clean, if at all.

**Bottom line:** personally I'd go fully strict in local + CI, and in production run a log-only handler for the first weeks. Even once telemetry is clean, leaving production on log-only is enough for most teams: you see the N+1s there without hitting anyone with a 500. The real rule: never flip strict throwing on cold in production — measure first, then tighten.

## Related Reading

- [Eloquent Relationships: hasMany, belongsTo, and Eager Loading](/blog/eloquent-relationships-hasmany-belongsto-and-eager-loading/) — Blog
- [Should I use chunkById instead of chunk when the same job also updates the rows it iterates?](https://muhammetsafak.com/just-ask/should-i-use-chunkbyid-instead-of-chunk-when-the-same-job/) — Just Ask
- [For comments across many models should I use a polymorphic relation or separate tables, given indexing and foreign keys?](https://muhammetsafak.com/just-ask/comments-polymorphic-relation-separate-tables-indexing-foreign-keys/) — Just Ask
- [Should I bind a Money value object to Eloquent with a custom cast or with accessors/mutators?](https://muhammetsafak.com/just-ask/should-i-bind-a-money-value-object-to-eloquent-with-a/) — Just Ask
