> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrationsleitfaden von der alten zur neuen Struktur

> Anleitung, um von der alten Anwendungsstruktur (Laravel 10) auf die Slim Application Skeleton ab Laravel 11 umzustellen.

## Einleitung

Dieser Leitfaden beschreibt, wie Sie von der alten Anwendungsstruktur (mit `Kernel`-Klassen und mehreren Service Providern) aus Laravel 10 auf die Slim Application Skeleton ab Laravel 11 umsteigen.

<Warning>
  **Die offizielle Dokumentation empfiehlt diese Migration nicht.**

  * Die alte Laravel-10-Struktur **läuft in Laravel 11 und höher weiter unverändert**. Auch in aktuellen Versionen bis Laravel 13 gibt es keinen End-of-Life-Plan.
  * Die Migration ist **vollständig optional** — sie ist weder Pflicht noch Empfehlung.
  * Ohne tiefes Verständnis der Unterschiede zwischen alter und neuer Struktur raten wir dringend davon ab. Das ist Arbeit für Entwickler, die die Framework-Interna gut kennen.
  * **Sichern Sie das Projekt vor der Migration**, und stellen Sie sicher, dass alle Tests grün sind.
</Warning>

## Wann eine Migration sinnvoll ist

In folgenden Fällen ist eine Migration überlegenswert:

* Neue Team-Mitglieder sollen mit der offiziellen Doku leichter arbeiten können — deshalb wollen Sie das Projekt auf die aktuelle Standardstruktur bringen.
* Sie möchten die Konsistenz zu Paketen oder Starter-Kits wahren, die ab Laravel 11 neu entstanden sind.
* Sie möchten Konfigurationsdateien und Klassen aus der Alt-Struktur reduzieren und die Codebasis vereinfachen.

## Voraussetzungen

Diese Anleitung setzt Folgendes voraus:

* **Der Laravel-Versions-Upgrade ist abgeschlossen** (`laravel/framework ^11.0` oder höher).
* Bestehende Tests laufen alle grün.
* Sie kennen die Anwendungsstruktur ab Laravel 11 (siehe [Anwendungsstruktur ab Laravel 11](/de/advanced/app-structure)).

## Migrationsbeispiel

Wir zeigen, wie ein mit Laravel 10 + Breeze (Blade-Stack) erstelltes Projekt Breeze behält und nur die Anwendungsstruktur migriert.

<Steps>
  <Step title="bootstrap/app.php ersetzen">
    Die alte `bootstrap/app.php` erzeugte die `$app`-Instanz und registrierte die Kernels. Ersetzen Sie das durch die
    `Application::configure()`-Chain.

    **Alt (Laravel 10):**

    ```php theme={null}
    <?php

    $app = new Illuminate\Foundation\Application(
        $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
    );

    $app->singleton(
        Illuminate\Contracts\Http\Kernel::class,
        App\Http\Kernel::class
    );

    $app->singleton(
        Illuminate\Contracts\Console\Kernel::class,
        App\Console\Kernel::class
    );

    $app->singleton(
        Illuminate\Contracts\Debug\ExceptionHandler::class,
        App\Exceptions\Handler::class
    );

    return $app;
    ```

    **Neu (Laravel 11 und höher):**

    ```php theme={null}
    <?php

    use Illuminate\Foundation\Application;
    use Illuminate\Foundation\Configuration\Exceptions;
    use Illuminate\Foundation\Configuration\Middleware;

    return Application::configure(basePath: dirname(__DIR__))
        ->withRouting(
            web: __DIR__.'/../routes/web.php',
            commands: __DIR__.'/../routes/console.php',
            health: '/up',
        )
        ->withMiddleware(function (Middleware $middleware) {
            //
        })
        ->withExceptions(function (Exceptions $exceptions) {
            //
        })->create();
    ```

    <Info>
      Die Callbacks `withMiddleware()` und `withExceptions()` sind die neuen Ablageorte für die Konfiguration aus den Kernel-Dateien, die wir in den nächsten Schritten löschen. Lassen Sie sie zunächst leer und ergänzen Sie sie im weiteren Verlauf.
    </Info>
  </Step>

  <Step title="HTTP-Kernel (app/Http/Kernel.php) löschen">
    `app/Http/Kernel.php` definierte globale Middleware, Middleware-Gruppen und Middleware-Aliase.

    **Alt (app/Http/Kernel.php):**

    ```php theme={null}
    <?php

    namespace App\Http;

    use Illuminate\Foundation\Http\Kernel as HttpKernel;

    class Kernel extends HttpKernel
    {
        protected $middleware = [
            \App\Http\Middleware\TrustProxies::class,
            \Illuminate\Http\Middleware\HandleCors::class,
            \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
            \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
            \App\Http\Middleware\TrimStrings::class,
            \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
        ];

        protected $middlewareGroups = [
            'web' => [
                \App\Http\Middleware\EncryptCookies::class,
                \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
                \Illuminate\Session\Middleware\StartSession::class,
                \Illuminate\View\Middleware\ShareErrorsFromSession::class,
                \App\Http\Middleware\VerifyCsrfToken::class,
                \Illuminate\Routing\Middleware\SubstituteBindings::class,
            ],
            'api' => [
                \Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
                \Illuminate\Routing\Middleware\SubstituteBindings::class,
            ],
        ];

        protected $middlewareAliases = [
            'auth' => \App\Http\Middleware\Authenticate::class,
            // ...
        ];
    }
    ```

    In Laravel 11 sind diese Middlewares bereits framework-intern als Defaults hinterlegt. Ohne eigene Anpassungen können Sie `app/Http/Kernel.php` einfach löschen.

    **Bei eigenen Anpassungen** (zusätzliche/ausgeschlossene Middleware) übertragen Sie diese in `withMiddleware()` in `bootstrap/app.php`, bevor Sie die Datei entfernen.

    ```php theme={null}
    ->withMiddleware(function (Middleware $middleware) {
        // Globale Middleware hinzufügen
        $middleware->append(\App\Http\Middleware\MyCustomMiddleware::class);

        // Middleware zur web-Gruppe hinzufügen
        $middleware->web(append: [
            \App\Http\Middleware\HandleInertiaRequests::class,
        ]);

        // Middleware-Alias hinzufügen
        $middleware->alias([
            'role' => \App\Http\Middleware\CheckRole::class,
        ]);
    })
    ```

    Nach dem Übertragen löschen Sie `app/Http/Kernel.php`.

    <Info>
      In Laravel 11 können Sie auch Standard-Middleware-Klassen wie `TrustProxies`, `EncryptCookies` und `VerifyCsrfToken` aus `app/Http/Middleware/` entfernen. Diese sind ins Framework integriert; ohne Anpassungen sind die Dateien überflüssig.
    </Info>
  </Step>

  <Step title="Console-Kernel (app/Console/Kernel.php) löschen">
    `app/Console/Kernel.php` war für die Scheduler-Definition und das Autoloading von Commands zuständig.

    **Alt (app/Console/Kernel.php):**

    ```php theme={null}
    <?php

    namespace App\Console;

    use Illuminate\Console\Scheduling\Schedule;
    use Illuminate\Foundation\Console\Kernel as ConsoleKernel;

    class Kernel extends ConsoleKernel
    {
        protected function schedule(Schedule $schedule): void
        {
            // $schedule->command('inspire')->hourly();
        }

        protected function commands(): void
        {
            $this->load(__DIR__.'/Commands');
            require base_path('routes/console.php');
        }
    }
    ```

    **Das Autoloading der Commands** ist ab Laravel 11 nicht mehr nötig: `app/Console/Commands/` wird automatisch gescannt.

    **Die Scheduler-Definition** verschieben Sie nach `routes/console.php` oder in `withSchedule()` in `bootstrap/app.php`.

    ```php theme={null}
    // routes/console.php (Laravel 11 und höher)
    use Illuminate\Support\Facades\Schedule;

    Schedule::command('emails:send')->daily();
    ```

    Nach der Migration löschen Sie `app/Console/Kernel.php`.

    <Info>
      Löschen Sie keine eigenen Artisan-Command-Dateien im Verzeichnis `app/Console/`. Belassen Sie die Command-Dateien und entfernen Sie nur die Kernel-Klasse.
    </Info>
  </Step>

  <Step title="Exception-Handler (app/Exceptions/Handler.php) löschen">
    `app/Exceptions/Handler.php` steuerte das Reporten und Rendern von Exceptions.

    **Alt (app/Exceptions/Handler.php):**

    ```php theme={null}
    <?php

    namespace App\Exceptions;

    use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
    use Throwable;

    class Handler extends ExceptionHandler
    {
        protected $dontFlash = [
            'current_password',
            'password',
            'password_confirmation',
        ];

        public function register(): void
        {
            $this->reportable(function (Throwable $e) {
                //
            });
        }
    }
    ```

    Bei eigenen Anpassungen übertragen Sie diese in `withExceptions()` in `bootstrap/app.php` und löschen dann die Datei.

    ```php theme={null}
    use Throwable;
    use Illuminate\Http\Request;

    ->withExceptions(function (Exceptions $exceptions) {
        // Anpassung des Exception-Reportings
        $exceptions->report(function (Throwable $e) {
            // ...
        });

        // Anpassung des Renderings
        $exceptions->render(function (\App\Exceptions\InvalidOrderException $e, Request $request) {
            return response()->view('errors.invalid-order', status: 500);
        });
    })
    ```

    Zusätzlich definierte `$dontFlash`-Einträge lassen sich ebenfalls übertragen.

    ```php theme={null}
    ->withExceptions(function (Exceptions $exceptions) {
        $exceptions->dontFlash([
            'my_sensitive_field',
        ]);
    })
    ```

    Nach dem Übertragen löschen Sie `app/Exceptions/Handler.php`.
  </Step>

  <Step title="RouteServiceProvider entfernen und Routen-Registrierung migrieren">
    `app/Providers/RouteServiceProvider.php` hat Routen-Dateien geladen und Rate Limits konfiguriert.

    **Alt (app/Providers/RouteServiceProvider.php):**

    ```php theme={null}
    <?php

    namespace App\Providers;

    use Illuminate\Cache\RateLimiting\Limit;
    use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\RateLimiter;
    use Illuminate\Support\Facades\Route;

    class RouteServiceProvider extends ServiceProvider
    {
        public const HOME = '/home';

        public function boot(): void
        {
            RateLimiter::for('api', function (Request $request) {
                return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
            });

            $this->routes(function () {
                Route::middleware('api')
                    ->prefix('api')
                    ->group(base_path('routes/api.php'));

                Route::middleware('web')
                    ->group(base_path('routes/web.php'));
            });
        }
    }
    ```

    **Die Registrierung der Routen-Dateien** verschieben Sie nach `withRouting()` in `bootstrap/app.php`.

    ```php theme={null}
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php', // wenn API-Routen genutzt werden
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ```

    **Rate Limits** wandern in `AppServiceProvider::boot()`.

    ```php theme={null}
    // app/Providers/AppServiceProvider.php
    use Illuminate\Cache\RateLimiting\Limit;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\RateLimiter;

    public function boot(): void
    {
        RateLimiter::for('api', function (Request $request) {
            return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
        });
    }
    ```

    Verwenden Sie die Konstante `HOME` an anderer Stelle, ersetzen Sie sie durch eine URL-Zeichenkette oder verschieben Sie die Konstante in den `AppServiceProvider`.

    Nach der Migration löschen Sie `app/Providers/RouteServiceProvider.php`.
  </Step>

  <Step title="Service Provider aufräumen">
    In Laravel 10 gab es standardmäßig fünf Service Provider. Fassen Sie diese im `AppServiceProvider.php` zu einem zusammen.

    **Zu entfernende Provider (Inhalte in AppServiceProvider verschieben, dann löschen):**

    | Datei                                        | Ziel                                                          |
    | -------------------------------------------- | ------------------------------------------------------------- |
    | `app/Providers/AuthServiceProvider.php`      | `Gate::policy()` u. Ä. in `AppServiceProvider::boot()`        |
    | `app/Providers/BroadcastServiceProvider.php` | Bei Broadcasting: `withBroadcasting()` in `bootstrap/app.php` |
    | `app/Providers/EventServiceProvider.php`     | `Event::listen()` u. Ä. in `AppServiceProvider::boot()`       |
    | `app/Providers/RouteServiceProvider.php`     | Im vorigen Schritt bereits behandelt                          |

    **Beispiel: Migration des `AuthServiceProvider`:**

    ```php theme={null}
    // Alt: app/Providers/AuthServiceProvider.php
    use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

    class AuthServiceProvider extends ServiceProvider
    {
        protected $policies = [
            Post::class => PostPolicy::class,
        ];

        public function boot(): void
        {
            $this->registerPolicies();
        }
    }
    ```

    ```php theme={null}
    // Neu: app/Providers/AppServiceProvider.php
    // Wenn Sie die Standard-Namenskonvention einhalten, ist das dank Auto-Discovery überflüssig
    use Illuminate\Support\Facades\Gate;

    class AppServiceProvider extends ServiceProvider
    {
        public function boot(): void
        {
            Gate::policy(Post::class, PostPolicy::class);
        }
    }
    ```

    Nachdem Sie die überflüssigen Provider-Dateien gelöscht haben, entfernen Sie das `providers`-Array aus `config/app.php`.

    ```php theme={null}
    // Das providers-Array in config/app.php
    // Kann komplett entfernt werden
    'providers' => ServiceProvider::defaultProviders()->merge([
    App\Providers\AppServiceProvider::class,
    // Die Einträge der gelöschten Provider ebenfalls entfernen
    // App\Providers\AuthServiceProvider::class, // entfernen
    // App\Providers\EventServiceProvider::class, // entfernen
    // App\Providers\RouteServiceProvider::class, // entfernen
    ])->toArray(),
    ```

    Legen Sie zusätzlich `bootstrap/providers.php` an, um die neue Struktur zu bedienen.

    ```php theme={null}
    <?php

    // bootstrap/providers.php
    return [
        App\Providers\AppServiceProvider::class,
    ];
    ```

    <Info>
      Existiert `bootstrap/providers.php`, verwendet Laravel diese Datei vorrangig als Provider-Liste.
    </Info>
  </Step>

  <Step title="Controller-Basisklasse aktualisieren">
    In Laravel 10 nutzte die `Controller`-Basisklasse die Traits `AuthorizesRequests` und `ValidatesRequests`. Die neue Basisklasse in Laravel 11 ist eine schlichte abstrakte Klasse ohne diese Traits.

    **Alt (Laravel 10):**

    ```php theme={null}
    <?php

    namespace App\Http\Controllers;

    use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
    use Illuminate\Foundation\Validation\ValidatesRequests;
    use Illuminate\Routing\Controller as BaseController;

    class Controller extends BaseController
    {
        use AuthorizesRequests, ValidatesRequests;
    }
    ```

    **Neu (Laravel 11 und höher):**

    ```php theme={null}
    <?php

    namespace App\Http\Controllers;

    abstract class Controller
    {
        //
    }
    ```

    Die von den Traits gelieferten Funktionen ersetzen Sie wie folgt:

    | Alte Vorgehensweise (per Trait)         | Neue Vorgehensweise                                                                                         |
    | --------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
    | `$this->validate($request, $rules)`     | `$request->validate($rules)`                                                                                |
    | `$this->authorize('update', $post)`     | `Gate::authorize('update', $post)`                                                                          |
    | `$this->authorizeResource(Post::class)` | Kein einfaches Äquivalent in Laravel 11 — belassen Sie `App\Http\Controllers\Controller` in Laravel-10-Form |

    Nutzen bestehende Controller Methoden aus den Traits, können Sie entweder die einzelnen Controller anpassen oder die Traits in der `Controller`-Basisklasse belassen. Sie müssen nicht alles auf einmal ändern.

    <Warning>
      Wenn von Breeze oder Jetstream generierte Auth-Controller `$this->validate()` oder `$this->authorize()` aufrufen, prüfen Sie das Verhalten unbedingt, bevor Sie die Basisklasse ändern.
    </Warning>
  </Step>

  <Step title="Überflüssige config-Dateien entfernen">
    Dateien, die Sie nicht vom Standard abweichend geändert haben — `config/cors.php`, `config/hashing.php`, `config/view.php` u. a. — können Sie entfernen. Angepasste Dateien belassen Sie.
  </Step>

  <Step title="public/index.php aktualisieren">
    Diese Datei wurde für die neue Struktur überarbeitet; ersetzen Sie sie komplett.

    ```php theme={null}
    <?php

    use Illuminate\Foundation\Application;
    use Illuminate\Http\Request;

    define('LARAVEL_START', microtime(true));

    // Determine if the application is in maintenance mode...
    if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
    require $maintenance;
    }

    // Register the Composer autoloader...
    require __DIR__.'/../vendor/autoload.php';

    // Bootstrap Laravel and handle the request...
    /** @var Application $app */
    $app = require_once __DIR__.'/../bootstrap/app.php';

    $app->handleRequest(Request::capture());
    ```
  </Step>

  <Step title="artisan aktualisieren">
    Ersetzen Sie auch die `artisan`-Datei vollständig.

    ```php theme={null}
    #!/usr/bin/env php
    <?php

    use Illuminate\Foundation\Application;
    use Symfony\Component\Console\Input\ArgvInput;

    define('LARAVEL_START', microtime(true));

    // Register the Composer autoloader...
    require __DIR__.'/vendor/autoload.php';

    // Bootstrap Laravel and handle the command...
    /** @var Application $app */
    $app = require_once __DIR__.'/bootstrap/app.php';

    $status = $app->handleCommand(new ArgvInput);

    exit($status);
    ```
  </Step>

  <Step title="tests/TestCase.php aktualisieren">
    Der Trait `CreatesApplication` wird nicht mehr benötigt.
    `tests/CreatesApplication.php` kann gelöscht werden.

    ```php theme={null}
    <?php

    namespace Tests;

    use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

    abstract class TestCase extends BaseTestCase
    {
        //
    }
    ```
  </Step>

  <Step title=".env, .env.example und phpunit.xml aktualisieren">
    `CACHE_DRIVER` heißt jetzt `CACHE_STORE`, und neue Einträge sind hinzugekommen. Passen Sie diese bei Bedarf an.
    Da diese Änderungen Config-Dateien und die Produktivumgebung betreffen, gehen Sie umsichtig vor.
    Sie müssen den Änderungen nicht zwanghaft folgen.
  </Step>

  <Step title="Funktionscheck">
    Prüfen Sie das Ergebnis in dieser Reihenfolge.

    ```shell theme={null}
    # Konfigurationscaches leeren
    php artisan config:clear
    php artisan route:clear
    php artisan cache:clear

    # Routen prüfen
    php artisan route:list

    # Tests ausführen
    php artisan test
    ```

    Bei Problemen stellen Sie die gelöschten Dateien aus dem Backup wieder her und prüfen die Fehlermeldungen.
  </Step>
</Steps>

## Projektstruktur nach der Migration

Die Struktur nach der Migration sieht so aus (Änderungen zur alten Struktur hervorgehoben):

```
app/
├── Console/
│   └── Commands/          ← Eigene Commands bleiben erhalten
│   (Kernel.php entfernt)
├── Exceptions/
│   (Handler.php entfernt)
├── Http/
│   ├── Controllers/
│   │   └── Controller.php ← Schlichte abstrakte Klasse
│   └── Middleware/        ← Eigene Middleware bleibt erhalten
│   (Kernel.php entfernt)
├── Models/
└── Providers/
    └── AppServiceProvider.php ← auf 1 Datei zusammengeführt
    (AuthServiceProvider.php entfernt)
    (BroadcastServiceProvider.php entfernt)
    (EventServiceProvider.php entfernt)
    (RouteServiceProvider.php entfernt)
bootstrap/
├── app.php                ← durch Application::configure() ersetzt
└── providers.php          ← neu angelegt
routes/
├── web.php
├── api.php                ← nur bei Bedarf
└── console.php            ← Scheduler-Definitionen hier
```

## Zusammenfassung

| Was migriert wird    | Alter Ort                                | Neuer Ort                                                           |
| -------------------- | ---------------------------------------- | ------------------------------------------------------------------- |
| HTTP-Middleware      | `app/Http/Kernel.php`                    | `withMiddleware()` in `bootstrap/app.php`                           |
| Exception-Handling   | `app/Exceptions/Handler.php`             | `withExceptions()` in `bootstrap/app.php`                           |
| Scheduler-Definition | `app/Console/Kernel.php`                 | `routes/console.php`                                                |
| Routen-Registrierung | `app/Providers/RouteServiceProvider.php` | `withRouting()` in `bootstrap/app.php`                              |
| Provider-Liste       | `providers`-Array in `config/app.php`    | `bootstrap/providers.php`                                           |
| Policy-Registrierung | `app/Providers/AuthServiceProvider.php`  | Automatische Registrierung; manuell in `AppServiceProvider::boot()` |
| Event-Listener       | `app/Providers/EventServiceProvider.php` | Automatische Registrierung; manuell in `AppServiceProvider::boot()` |

## Weiterführende Links

* [Anwendungsstruktur ab Laravel 11](/de/advanced/app-structure)
* [FAQ zur neuen App-Struktur](/de/advanced/app-structure-faq)
* [Offizieller Upgrade Guide (11.x)](https://github.com/laravel/docs/blob/11.x/upgrade.md)
* [Diff im Repo laravel/laravel 10.x → 11.x](https://github.com/laravel/laravel/compare/10.x...11.x)
* [Controller.php in Laravel 10](https://github.com/laravel/laravel/blob/10.x/app/Http/Controllers/Controller.php)
* [Controller.php in Laravel 11](https://github.com/laravel/laravel/blob/11.x/app/Http/Controllers/Controller.php)


## Related topics

- [FAQ zur neuen App-Struktur ab Laravel 11](/de/advanced/app-structure-faq.md)
- [Anwendungsstruktur ab Laravel 11](/de/advanced/app-structure.md)
- [Übersicht der neuen Features in Laravel 13](/de/blog/laravel-13-new-features.md)
- [Migrations-Guide von laravel/ui zu Fortify](/de/blog/ui-to-fortify.md)
- [Laravel Cloud – Der Gesamtüberblick zum Laravel-eigenen PaaS](/de/blog/laravel-cloud.md)
