Which bootstrappers does the Laravel 13 HTTP kernel run, in what order, and why does that order matter to your own code?
answer
- six classes in Kernel::$bootstrappers
- environment before configuration
- facades before providers
- all registered, then all booted
- framework, then packages, then app providers
basics
~10 sLoadEnvironmentVariables, LoadConfiguration, HandleExceptions, RegisterFacades, RegisterProviders, BootProviders. So .env is read before config files, errors are handled before providers run, and every eager provider is registered before any provider boots.
solid answer
~40 s`Illuminate\Foundation\Http\Kernel::$bootstrappers` lists six classes, run in order by `bootstrapWith()` the first time `handle()` runs on an application: `LoadEnvironmentVariables` reads `.env`, `LoadConfiguration` loads `config/*.php` (or the cached config), `HandleExceptions` installs PHP error and exception handlers, `RegisterFacades` wires facades and aliases, `RegisterProviders` merges `bootstrap/providers.php` into the provider list and registers every eager provider (deferred ones wait until their services are needed), and `BootProviders` boots them. The order explains common rules: config files can call `env()` because the environment is loaded first; a provider's `register()` may run before other providers exist, while `boot()` can rely on every binding; and providers are ordered framework first, then package-discovered ones, then your own. The console kernel adds `SetRequestForConsole` before registering providers.
code
php · 11 lines<?php
// Illuminate\Foundation\Http\Kernel (framework source, Laravel 13)
protected $bootstrappers = [
\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
\Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
\Illuminate\Foundation\Bootstrap\HandleExceptions::class,
\Illuminate\Foundation\Bootstrap\RegisterFacades::class,
\Illuminate\Foundation\Bootstrap\RegisterProviders::class,
\Illuminate\Foundation\Bootstrap\BootProviders::class,
];go deeper
Remember that the environment and config are loaded first and providers last, and that eager providers all register before any of them boots.
List the six bootstrappers in order, explain the framework-packages-app provider ordering, and connect the order to where env(), facades and bindings can be used.
Diagnose ordering bugs, such as a provider resolving a binding in register() or code in bootstrap/app.php using config, by reading the bootstrap sequence.
Set conventions for provider granularity and ordering in a large app so boot-time dependencies stay predictable as packages are added.
## Where bootstrapping happens Building the application in `bootstrap/app.php` does not load settings or providers. That work is done by **bootstrappers**, small classes the kernel runs through `Application::bootstrapWith()` the first time it handles a request. In the HTTP kernel, `sendRequestThroughRouter()` calls `bootstrap()`, which checks `hasBeenBootstrapped()` and, if needed, runs the list in `Kernel::$bootstrappers`. ## The six HTTP bootstrappers 1. **`LoadEnvironmentVariables`** loads `.env` (or the file for the current environment) into the process environment; it is skipped when configuration is cached. 2. **`LoadConfiguration`** loads every `config/*.php` file, merged with the framework's defaults, or the cached configuration if it exists. 3. **`HandleExceptions`** installs Laravel's PHP error, exception and shutdown handlers. 4. **`RegisterFacades`** clears resolved facade instances, points facades at the application and registers class aliases. 5. **`RegisterProviders`** builds the provider list and calls `register()` on each eager provider; deferred providers are only recorded until one of their services is requested. 6. **`BootProviders`** calls `Application::boot()`, which fires `booting` callbacks, calls `boot()` on every registered provider, and fires `booted` callbacks. The console kernel runs the same list with **`SetRequestForConsole`** inserted before `RegisterProviders`, so URL generation works in commands. ## How the provider list is built `RegisterProviders` merges the providers from `bootstrap/providers.php` into `app.providers` (skipped when configuration comes from the cache, which already contains them), and `registerConfiguredProviders()` orders them: | Position | Providers | |---|---| | First | Framework providers (`Illuminate\...`) | | Second | Providers from package auto-discovery | | Last | Your application's providers, e.g. `App\Providers\AppServiceProvider` | Your provider therefore registers after every framework and package provider, and in the boot phase it boots after them too. ## Why the order matters - **`env()` in config files works** because the environment is loaded in step 1, before configuration in step 2. - **Errors during provider code are handled by Laravel**, because step 3 installs the handlers before steps 5 and 6 run. - **Facades can be used in `boot()`**, because step 4 has run; they are also technically set up during `register()`, but the services behind them may not be registered yet. - **Every eager provider registers before any boots.** Code in `boot()` can resolve any binding from any provider; code in `register()` should only bind, because the provider it needs may come later in the list. What belongs in `register()` versus `boot()` in detail is a separate subject; here the point is the sequence that makes that rule necessary. ## Hooks around the boot pass `Application::boot()`, called by the `BootProviders` bootstrapper, does three things in order: 1. fires callbacks registered with `$app->booting(...)`; 2. boots each registered provider (its booting callbacks, its `boot()` method, then its booted callbacks); 3. marks the application as booted and fires callbacks registered with `$app->booted(...)`. A `booted` callback is therefore the point where every registered provider has finished `boot()`. Calling `boot()` a second time does nothing, because the method returns early once the application is booted, and the kernel's own `bootstrap()` is guarded by `hasBeenBootstrapped()` in the same way. ## A ticket-resale example A ticket-resale app's `AppServiceProvider::boot()` registers a response macro for the `X-Queue-Position` header and reads `config('tickets.queue_enabled')`. Both work there: configuration was loaded in step 2 and every eager provider was registered in step 5. Moving the same code to the top of `bootstrap/app.php` fails, because none of the bootstrappers have run when that file executes. ## Common misreadings - "Providers boot in the order they register, one at a time": the eager providers all register first, then they all boot. - "`bootstrap/app.php` runs the bootstrappers": the kernel does, inside `handle()`. - "My provider runs first because it is in my app": application providers come after framework and package providers.
- What does the console kernel bootstrap differently from the HTTP kernel?The console kernel's list is the same six bootstrappers plus `SetRequestForConsole`, placed after `RegisterFacades` and before `RegisterProviders`. It binds a request built from the `app.url` config value, so URL helpers such as `route()` and `url()` produce the right absolute links while an Artisan command runs.
- In what order are a Laravel 13 app's service providers registered?`registerConfiguredProviders()` splits the configured list into framework providers (names starting with `Illuminate\`) and the rest, inserts the providers from the package manifest after the framework ones, and registers them in that order: framework, then packages, then the app's own providers such as `AppServiceProvider`. Booting later follows the same order.
saying these in an interview costs you the question
- Config files are loaded before .env, so env() returns null in them
- Each provider boots right after it registers
- bootstrap/app.php runs the bootstrappers when it is required
- AppServiceProvider registers before the framework providers
- The console kernel skips provider booting for speed