skip to content

Which bootstrappers does the Laravel 13 HTTP kernel run, in what order, and why does that order matter to your own code?

level: middleimportance: should knowfreq 40%

answer

  1. six classes in Kernel::$bootstrappers
  2. environment before configuration
  3. facades before providers
  4. all registered, then all booted
  5. framework, then packages, then app providers

basics

~10 s

LoadEnvironmentVariables, 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
<?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

for a junior

Remember that the environment and config are loaded first and providers last, and that eager providers all register before any of them boots.

for a middle

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.

for a senior

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.

for a principal

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