laravel-providers

Installation
SKILL.md

Laravel Providers

Application setup has two homes. AppServiceProvider sets the app-wide defaults: how models behave, which date class the app uses, the morph map, rate limiters and local debug tooling. Booters, small invokable classes in app/Booters/, replace the closures Laravel puts in bootstrap/app.php for middleware, the schedule and exceptions. Both stay readable because each concern sits in its own named method or class.

Rules

  • Named methods. register() and boot() only call private register{Thing}() and boot{Thing}() methods, one per concern: bootMorphMaps(), bootModelConfig(), bootDates(), bootRateLimiters(), bootDebug(). Then boot() reads as a table of contents.
  • Models are unguarded. Call Model::unguard() once, and never put $fillable or $guarded on a model. Mass-assignment safety comes from typed input (Form Request, then DTO), never from raw request arrays.
  • Lazy loading is prevented locally. Call Model::preventLazyLoading($this->app->isLocal()) and report violations to Ray (or the log, where the project doesn't use Ray) rather than throwing, so you see an N+1 while you work without the page breaking. Production pays nothing.
  • The morph map is enforced. Use Relation::enforceMorphMap() and key every entry by the model's PascalCase class basename: 'Order' => Order::class. An unmapped model then throws instead of storing its class name, and a namespace move can't orphan stored rows. A model goes in as soon as it joins any polymorphic relation, including the ones packages create: Sanctum's tokenable, notifications, activity or media logs.
  • Dates are immutable. Call Date::use(CarbonImmutable::class), so now(), today() and every date cast return CarbonImmutable. As a result, type-hint dates as CarbonInterface or CarbonImmutable, never Carbon, which throws a TypeError on the first cast value it receives. Create dates with now(), today() or Date::parse(). Carbon::parse() returns a mutable instance.
  • Rate limiters live in AppServiceProvider::bootRateLimiters(). Every limiter goes there, including a service's own, so they're all registered on every request and in every worker.
  • Macros live in one MacroServiceProvider. One place to find every method the app adds to framework classes.
  • Debug tooling is local only. Ray query watchers and dev-only providers are guarded by $this->app->isLocal() or an environment check.
  • bootstrap/app.php wires booters, not closures. withMiddleware, withSchedule and withExceptions each take an invokable booter. Route surfaces are registered through withRouting(), which laravel-routing owns.
  • Name every scheduled callback. Every ->call() gets a ->name(). withoutOverlapping() and onOneServer() throw on an unnamed callback, and the name is what schedule:list shows. Follow the project's naming style, whether class names or descriptions.

Example

Installs
56
GitHub Stars
15
First Seen
Mar 27, 2026