Skip to content

Stricter Laravel Defaults ​

Published on: September 17, 2026



Laravel is flexible by default — sometimes too flexible. Out of the box, it lets you quietly access missing model attributes, lazy load relationships without warning, and run destructive database commands in production. That flexibility is convenient early on, but it becomes a liability as your app grows.

The fix is simple: tighten up your defaults in AppServiceProvider.

Why It Matters ​

As AI-assisted coding becomes part of everyday development, sloppy defaults carry even more risk. Code generated by an AI (or written quickly by a human) can silently do the wrong thing if the framework isn't configured to catch mistakes early. Stricter defaults turn silent failures into loud, catchable errors.

The Defaults Worth Changing ​

1. Strict Models ​

php
Model::shouldBeStrict();

This single line enables three protections at once: it throws an exception when you access an attribute that doesn't exist on the model, prevents lazy loading (so N+1 queries don't sneak past you), and raises an error if you try to set an attribute that isn't fillable. What used to fail silently now fails immediately.

2. Immutable Dates with CarbonImmutable ​

php
Date::use(CarbonImmutable::class);

By default, Carbon dates are mutable objects — pass one into a service or helper, and any modification inside that call changes the original too. CarbonImmutable treats dates as values rather than references: every operation returns a new instance and leaves the one you passed in untouched. It's a small switch that eliminates a whole class of subtle, hard-to-trace bugs.

3. Stronger Password Rules ​

php
Password::defaults(function () {
    return Password::min(15)          // 15+ if no MFA, 8+ if MFA is enforced
        ->max(64)                     // cap to avoid long-password DoS on the hasher
        ->uncompromised();            // checks against Pwned Passwords
});

OWASP recommends a minimum length of 15 characters (or 8 if MFA is enforced), a max of at least 64, no forced composition rules, and screening against breached password lists. Setting the above once in AppServiceProvider means every Password::defaults() call site (registration, password reset, etc.) inherits that baseline.

4. Block Destructive Commands in Production ​

php
DB::prohibitDestructiveCommands(
    $this->app->isProduction()
);

Commands like migrate:fresh and db:wipe have no business running against a production database. This flag blocks them entirely when the environment is production, removing the possibility of a catastrophic mistake.

5. Prevent Stray HTTP Requests in Tests ​

php
Http::preventStrayRequests(
    $this->app->runningUnitTests()
);

Without this, your tests can silently make real HTTP calls, leading to flaky tests, slow suites, and unexpected side effects. With it enabled, any unmocked request throws an exception, forcing you to be explicit about external dependencies.

The Lazy Option: Laravel Essentials ​

If you'd rather not configure each of these by hand, Nuno Maduro's Laravel Essentials package applies many of these recommended defaults automatically. Install it, and you get a sensible, stricter baseline without the boilerplate.

Beyond the settings covered above, Essentials also ships with a few extras worth knowing about:

  • Auto Eager Loading — automatically eager-loads relationships without needing with() scattered throughout your codebase.
  • Force HTTPS — forces all generated URLs to use https://, ensuring your app doesn't accidentally serve insecure links.
  • Asset Prefetching — configures Laravel Vite to preload assets more aggressively, improving front-end load times out of the box.
  • Fake Sleep — fakes the Sleep facade during tests, preventing unexpected delays.
  • Optional Unguarded Models — an opt-in flag to disable mass-assignment protection globally, handy in situations where maintaining $fillable lists adds more noise than value.

All features are individually toggleable via config/essentials.php, so you can adopt only what makes sense for your project.

The Takeaway ​

The goal isn't to restrict Laravel's flexibility — it's to catch mistakes early.

A few changes in AppServiceProvider turn common failure modes into immediate, actionable errors: N+1 queries become visible, dates can't be mutated accidentally, weak or compromised passwords are rejected, destructive commands are blocked in production, and unexpected HTTP requests fail in tests.

That's useful whether the code comes from a human or an AI. They make Laravel's defaults more defensive, so mistakes are caught early instead of quietly making their way into production.