Das komplette Bild der mit Laravel 11 eingeführten Slim Application Skeleton sowie die interne Implementierung von Application::configure() bis zum ApplicationBuilder.
Mit Laravel 11 wurde die Anwendungsstruktur als „Slim Application Skeleton” grundlegend überarbeitet. Die größte Änderung: verstreute Einstellungen werden nun an einer einzigen Stelle in bootstrap/app.php gebündelt.
Aspekt
Laravel 10 und älter
Laravel 11 und höher
HTTP-Kernel
app/Http/Kernel.php
Entfällt (in das Framework integriert)
Console-Kernel
app/Console/Kernel.php
Entfällt (in routes/console.php verschoben)
Exception-Handler
app/Exceptions/Handler.php
Entfällt (in bootstrap/app.php gebündelt)
Service Provider
5 Dateien
Nur noch AppServiceProvider.php
Routen-Dateien
web.php / api.php standardmäßig
Nur web.php standard, api.php per Opt-in
Bootstrap
Einstellungen auf mehrere Dateien verteilt
In bootstrap/app.php gebündelt
Standard-DB
MySQL/PostgreSQL
SQLite
Diese Änderung betrifft neue Projekte. Bestehende Laravel-10-Anwendungen laufen nach einem Upgrade in ihrer alten Struktur weiter.
Mit dieser einen Datei konfigurieren Sie Routing, Middleware und Exception-Handling. Was in Laravel 10 auf app/Http/Kernel.php, app/Console/Kernel.php und app/Exceptions/Handler.php verteilt war, ist hier zusammengefasst.
Diese Datei registriert die Service Provider. In Laravel 10 stand das im providers-Array von config/app.php; jetzt ist es in bootstrap/providers.php getrennt. Standardmäßig ist nur der AppServiceProvider eingetragen.
Beim composer require eines Pakets aktualisiert dieses ggf. bootstrap/providers.php automatisch. config/app.php wird zwar noch gelesen, aber Neuregistrierungen erfolgen bevorzugt in bootstrap/providers.php.
Der HTTP-Kernel ist in Illuminate\Foundation\Http\Kernel im Framework integriert. Middleware-Anpassungen erfolgen über withMiddleware() in bootstrap/app.php.
Die beiden Aufgaben des Console-Kernels sind getrennt: Artisan-Commands liegen in app/Console/Commands/ und werden automatisch erkannt, Scheduler-Definitionen stehen in routes/console.php.
// Laravel 10: app/Console/Kernel.phpprotected function schedule(Schedule $schedule): void{ $schedule->command('emails:send')->daily();}
Der Exception-Handler ist in Illuminate\Foundation\Exceptions\Handler im Framework integriert. Anpassungen erfolgen über withExceptions() in bootstrap/app.php.
Application::configure() ist eine statische Methode von Illuminate\Foundation\Application.
// Aus Illuminate\Foundation\Applicationpublic static function configure(?string $basePath = null){ $basePath = match (true) { is_string($basePath) => $basePath, default => static::inferBasePath(), }; return (new Configuration\ApplicationBuilder(new static($basePath))) ->withKernels() ->withEvents() ->withCommands() ->withProviders();}
Die Methode:
Bestimmt aus basePath das Wurzelverzeichnis der Anwendung.
Erzeugt eine Application-Instanz.
Verpackt sie in einem ApplicationBuilder und wendet Standardeinstellungen an.
Gibt den ApplicationBuilder zurück.
Wichtig: In configure() werden bereits withKernels(), withEvents(), withCommands() und withProviders() aufgerufen — in bootstrap/app.php müssen Sie sie nicht erneut aufrufen.
Application::configure(basePath: dirname(__DIR__)) // liefert ApplicationBuilder ->withRouting(...) // konfiguriert Routing, gibt $this zurück ->withMiddleware(...) // konfiguriert Middleware, gibt $this zurück ->withExceptions(...) // konfiguriert Exception-Handling, gibt $this zurück ->create(); // gibt die Application-Instanz zurück
create() extrahiert aus dem ApplicationBuilder die Application; genau diese Instanz gibt bootstrap/app.php per return zurück.
public/index.php ist der Einstiegspunkt; die Datei lädt bootstrap/app.php und erhält die Application. Danach führt der HTTP-Kernel den Request durch die Middleware-Pipeline, der Router dispatched an den Controller.
public function withMiddleware(?callable $callback = null){ $this->app->afterResolving(HttpKernel::class, function ($kernel) use ($callback) { $middleware = (new Middleware) ->redirectGuestsTo(fn () => route('login')); if (! is_null($callback)) { $callback($middleware); } $kernel->setGlobalMiddleware($middleware->getGlobalMiddleware()); $kernel->setMiddlewareGroups($middleware->getMiddlewareGroups()); $kernel->setMiddlewareAliases($middleware->getMiddlewareAliases()); // ... }); return $this;}
withMiddleware() führt den Callback aus, nachdem der HttpKernel aufgelöst wurde — mittels afterResolving(). Dem Callback wird ein Middleware-Objekt mit vielen Anpassungsmethoden übergeben.
->withMiddleware(function (Middleware $middleware) { // Globale Middleware anhängen $middleware->append(MyGlobalMiddleware::class); // Middleware zur web-Gruppe hinzufügen $middleware->web(append: [EnsureUserIsSubscribed::class]); // Middleware in der api-Gruppe ersetzen $middleware->api(replace: [ OldMiddleware::class => NewMiddleware::class, ]); // Pfade vom CSRF-Schutz ausnehmen $middleware->validateCsrfTokens(except: ['stripe/*', 'webhook/*']); // Weiterleitung für Gäste ändern $middleware->redirectGuestsTo('/custom-login'); // Priorität setzen $middleware->priority([ \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, ]);})
public function withExceptions(?callable $using = null){ $this->app->singleton( \Illuminate\Contracts\Debug\ExceptionHandler::class, \Illuminate\Foundation\Exceptions\Handler::class ); if ($using !== null) { $this->app->afterResolving( \Illuminate\Foundation\Exceptions\Handler::class, fn ($handler) => $using(new Exceptions($handler)), ); } return $this;}
withExceptions() registriert die Handler-Klasse als Singleton und setzt den Callback per afterResolving(). Dem Callback wird ein Exceptions-Wrapper übergeben.
->withExceptions(function (Exceptions $exceptions) { // Bestimmte Exceptions nicht melden $exceptions->dontReport(MissedFlightException::class); // Eigenes Reporting für bestimmte Exceptions $exceptions->report(function (InvalidOrderException $e) { // z. B. Slack benachrichtigen }); // HTTP-Response bestimmter Exceptions anpassen $exceptions->render(function (NotFoundHttpException $e, Request $request) { if ($request->is('api/*')) { return response()->json(['message' => 'Not Found'], 404); } }); // Throttling (nicht dieselbe Exception in Folge melden) $exceptions->throttle(function (Throwable $e) { return Limit::perMinute(20); });})
public function withProviders(array $providers = [], bool $withBootstrapProviders = true){ RegisterProviders::merge( $providers, $withBootstrapProviders ? $this->app->getBootstrapProvidersPath() : null ); return $this;}
Da withProviders() innerhalb von Application::configure() automatisch aufgerufen wird, lädt Laravel bootstrap/providers.php von selbst. Für zusätzliche Provider rufen Sie es in bootstrap/app.php explizit auf.
In app/Http/Kernel.php (Laravel 10) wurde Middleware als Array aufgelistet — eher wie eine Config-Datei. Das erschwerte Typunterstützung und IDE-Feedback.In Laravel 11 hat sich das zu einem Callback-Stil geändert: withMiddleware(function (Middleware $middleware) { ... }). So funktioniert Typvervollständigung, und Sie schreiben Verzweigungen oder Schleifen natürlich für dynamische Konfiguration.
Von „Convention over Configuration” zu „Explicit Configuration”
api.php ist Opt-in geworden, damit Anwendungen ohne API-Routen nicht permanent die api-Middleware-Gruppe laden. Was nicht gebraucht wird, existiert per Default nicht.
withMiddleware() und withExceptions() verwenden afterResolving(), um Konfigurationsreihenfolge-Probleme zu vermeiden. Die Methoden am ApplicationBuilder werden vor dem vollständigen Start aufgerufen; die tatsächliche Anwendung erfolgt verzögert beim ersten Auflösen des Kernels.
registered(), booting() und booted() am ApplicationBuilder registrieren nur Callbacks. Üblicherweise braucht man sie nicht, aber sie erlauben Sonderfälle — etwa Anpassungen am bereits gebooteten Kernel per booted().