In Laravel 13, how does bootstrap/providers.php decide which service providers load, and what does php artisan make:provider change in it?
answer
- slim skeleton, not config/app.php
- returns an array of provider classes
- make:provider adds and sorts it
- framework, then packages, then app
- cached config freezes the provider list
basics
~20 sbootstrap/providers.php returns the array of the app's own provider classes; the skeleton lists only AppServiceProvider. php artisan make:provider creates the class and adds it to that file. Framework defaults and auto-discovered package providers load before these.
solid answer
~40 sSince Laravel 11 the slim skeleton has no `providers` array in `config/app.php`; `Application::configure()` calls `withProviders()`, which points the `RegisterProviders` bootstrapper at `bootstrap/providers.php`. That file returns an array of class names, and the skeleton lists only `App\Providers\AppServiceProvider`. `php artisan make:provider NewsletterServiceProvider` writes the class to `app/Providers` and rewrites the file with the new entry, de-duplicated and sorted alphabetically. At startup the framework's default providers register first, then providers discovered from installed packages, then the app's list. Two traps: after `config:cache`, the file is not read at all because the list is baked into the cached `app.providers` value, so re-cache after adding a provider; and a provider class created by hand must be added to the file yourself.
code
bash · 5 linesphp artisan make:provider NewsletterServiceProvider
# app/Providers/NewsletterServiceProvider.php created
# bootstrap/providers.php now lists AppServiceProvider and NewsletterServiceProvider, sorted
php artisan config:cache # re-run on servers that cache configgo deeper
Recall that app providers are listed in bootstrap/providers.php and that make:provider adds the new class there for you.
Explain the load order, framework then package then app providers, and how a cached config freezes the provider list until it is rebuilt.
Anticipate deploy-time surprises: providers missing under a stale config cache, silently skipped class names, and order dependencies broken by re-sorting.
Decide which providers are always listed and which are registered conditionally per environment, keeping development tooling out of production bootstraps.
## Where providers are listed now Before Laravel 11, application providers were listed in a `providers` array inside `config/app.php`. The **slim skeleton** introduced in Laravel 11, and used by Laravel 13, moved them to their own file: ```php // bootstrap/providers.php return [ App\Providers\AppServiceProvider::class, ]; ``` The skeleton's `config/app.php` has no `providers` key, and `bootstrap/app.php` never mentions providers explicitly: `Application::configure()` already calls `withProviders()`, which tells the `RegisterProviders` bootstrapper where the file is. ## How the list is assembled at startup 1. `RegisterProviders` starts from `config('app.providers')`, or the framework's default provider list when that key is absent. 2. It appends any providers passed to `withProviders([...])` in `bootstrap/app.php`. 3. It appends the classes returned by `bootstrap/providers.php`, **dropping any entry whose class does not exist**. 4. The application splits the result into three groups, in this order: the framework's `Illuminate\` providers, then providers auto-discovered from installed packages, then everything else (your app). 5. Deferred providers are held back; the rest are registered in that order, then booted. Step 1 has a condition: when configuration is **cached**, steps 2 and 3 are skipped, because the merged list was saved into the cached `app.providers` value when `config:cache` ran. ## What make:provider does - Generates `app/Providers/NewsletterServiceProvider.php` with empty `register()` and `boot()` methods. - Re-reads `bootstrap/providers.php`, adds the new class, removes duplicates, **sorts** the list alphabetically and writes the file back. - Does nothing to the file if the class generation fails (for example the class exists and `--force` was not given). Because the file is rewritten sorted, the order of app providers is alphabetical after any `make:provider` run, so code should never depend on one app provider registering before another. ## Why the list moved out of config/app.php - **A smaller config.** The slim skeleton ships only the configuration most apps change; the long list of framework providers now comes from the framework's own defaults instead of being copied into every app. - **Only your providers are visible.** The file contains just the application's providers, so it is obvious what the app adds on top of the framework and its packages. - **Machine-editable.** Because the file is nothing but a returned array, `make:provider` can rewrite it safely. The rewrite regenerates the whole file from the array, so **comments you add there are lost** the next time the command runs. - **Package discovery is unchanged.** Packages still declare their providers in their `composer.json`, and those are discovered without touching this file. ## Conditional providers A provider needed only in some environments is usually registered from another provider rather than listed in the file: ```php public function register(): void { if ($this->app->environment('local')) { $this->app->register(\Laravel\Telescope\TelescopeServiceProvider::class); } } ``` `$this->app->register()` registers the provider immediately, and boots it too if the application has already booted. ## Traps | Situation | Effect | Fix | |---|---|---| | Provider added after `config:cache` | Ignored until the cache is rebuilt | `php artisan config:cache` or `optimize` | | Class name misspelled or package removed | Entry silently skipped, no error | Check the class exists; watch for missing behaviour | | Provider class created by hand | Never loaded | Add it to `bootstrap/providers.php` | | Relying on app provider order | Breaks when the list is re-sorted | Move dependent work into `boot()` | | Listing a package provider that is also auto-discovered | Registered once; the duplicate is harmless but redundant | Remove the manual entry | | Comments added to `bootstrap/providers.php` | Erased the next time `make:provider` rewrites the file | Keep notes in the provider classes instead |
- In Laravel 13, what happens if bootstrap/providers.php lists a class that no longer exists, such as a removed package's provider?The `RegisterProviders` bootstrapper checks each entry with `class_exists()` and silently drops any that fail, so the app still starts. The flip side is that a typo in a provider name produces no error; the provider's bindings and boot logic are simply missing.
- In Laravel, why is a provider added to bootstrap/providers.php ignored on a server that ran php artisan config:cache?When configuration is cached, the bootstrapper skips merging the bootstrap file and uses the provider list saved in the cached `app.providers` value. The new provider appears only after the configuration is cached again, which is why deploy scripts re-run `config:cache` or `optimize` on every release.
saying these in an interview costs you the question
- In Laravel 13 you add providers to the providers array in config/app.php.
- make:provider only creates the class; you must always edit bootstrap/providers.php by hand.
- App providers in bootstrap/providers.php register before the framework's own providers.
- A misspelled class in bootstrap/providers.php makes the app fail to boot with a clear error.
- Editing bootstrap/providers.php takes effect immediately even with a cached config.