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

# Upgrade-Anleitung von Laravel 12 auf 13

> Wir erläutern die Upgrade-Schritte, Breaking Changes, Deprecations und Highlights der neuen Features beim Wechsel von Laravel 12 auf Laravel 13.

## Einleitung

Laravel 13 wurde im März 2026 veröffentlicht. Dieser Leitfaden beschreibt die Upgrade-Schritte von Laravel 12.x auf 13.x.

<Info>
  Der geschätzte Zeitaufwand liegt bei **etwa 10 Minuten**. Die tatsächliche Auswirkung der Breaking Changes hängt jedoch vom Umfang und den genutzten Funktionen ab.
</Info>

### KI-gestütztes Upgrade

Sie können das Upgrade auch mit [Laravel Boost](https://github.com/laravel/boost) automatisieren. Boost ist ein First-Party-MCP-Server, der KI-Assistenten schrittweise Upgrade-Prompts bereitstellt. Nach der Installation in einer Laravel-12-Anwendung starten Sie in Claude Code, Cursor, OpenCode, Gemini oder VS Code das Upgrade über den Slash-Befehl `/upgrade-laravel-v13`. Der Befehl setzt `laravel/boost ^2.0` voraus.

Auch KI-Tools ohne Slash-Command-Unterstützung können denselben Ablauf ausführen, wenn Sie die Prompt-Datei direkt referenzieren. Fügen Sie folgenden Prompt in Ihre KI ein.

```text Prompt theme={null}
Lies den von Laravel Boost bereitgestellten Prompt ein und führe das Upgrade von Laravel 12 auf 13 durch.
https://raw.githubusercontent.com/laravel/boost/refs/heads/main/src/Mcp/Prompts/UpgradeLaravelv13/upgrade-laravel-v13.blade.php

- Übernimm die Änderungen aus dem `laravel/laravel`-Skelett. Verwende nicht master, sondern den 13.x-Branch.
- `database/migrations/*_create_cache_table.php`: keine Änderung, sondern eine neue Migration anlegen.
- In `config/session.php` `serialization` auf `php` setzen: `'serialization' => 'php'`.
- Die in Laravel 13 am häufigsten Fehler auslösende Änderung betrifft den Cache. Durchsuche die Cache-Nutzungen im Projekt und trage – wo unbedenklich – die Klassen in `config/cache.php` unter `serializable_classes` als erlaubt ein.

'serializable_classes' => [
    App\Data\CachedDashboardStats::class,
    App\Support\CachedPricingSnapshot::class,
    Illuminate\Support\Collection::class,
    Illuminate\Database\Eloquent\Collection::class,
],
```

***

## Änderungen nach Auswirkung

### Auswirkung: Hoch

* Aktualisierung der Abhängigkeiten
* Aktualisierung des Laravel-Installers
* Request Forgery Prevention (CSRF)

### Auswirkung: Mittel

* Cache-Einstellung `serializable_classes`
* Session-Einstellung `serialization`

### Auswirkung: Niedrig

* Cache-Präfix und Session-Cookie-Name
* Serialisierung von Model-Collections
* `Container::call` und nullable Klassen-Defaults
* Priorität registrierter Domain-Routen
* Exception-Payload im Event `JobAttempted`
* Binding von Manager-`extend`-Callbacks
* MySQL-`DELETE`-Queries (JOIN / ORDER BY / LIMIT)
* View-Namen der Bootstrap-Paginierung
* Benennung polymorpher Pivot-Tabellen
* Umbenennung von Properties im Event `QueueBusy`
* Reset der `Str`-Factory zwischen Tests

***

## Upgrade-Schritte

### Abhängigkeiten aktualisieren

**Auswirkung: Hoch**

Aktualisieren Sie in `composer.json` folgende Abhängigkeiten.

```json theme={null}
{
  "require": {
    "laravel/framework": "^13.0",
    "laravel/tinker": "^3.0"
  },
  "require-dev": {
    "phpunit/phpunit": "^12.0",
    "pestphp/pest": "^4.0"
  }
}
```

Wenn Sie Laravel Boost verwenden, aktualisieren Sie es ebenfalls.

```json theme={null}
{
  "require": {
    "laravel/boost": "^2.0"
  }
}
```

Installieren Sie anschließend die Abhängigkeiten:

```shell theme={null}
composer update
```

***

### Laravel-Installer aktualisieren

**Auswirkung: Hoch**

Wenn Sie neue Laravel-Anwendungen mit dem Laravel-Installer-CLI erstellen, aktualisieren Sie diesen auf eine Version mit Laravel-13.x-Unterstützung.

Wenn per `composer global require` installiert:

```shell theme={null}
composer global update laravel/installer
```

Wenn Sie die Bundled-Version von [Laravel Herd](https://herd.laravel.com) verwenden, aktualisieren Sie Herd auf die neueste Version.

***

## Breaking Changes

### Sicherheit

#### Request Forgery Prevention

**Auswirkung: Hoch**

Die CSRF-Middleware in Laravel wurde von `VerifyCsrfToken` in `PreventRequestForgery` umbenannt. Zusätzlich wurde die Prüfung der Anfrageherkunft über den Header `Sec-Fetch-Site` ergänzt.

`VerifyCsrfToken` und `ValidateCsrfToken` bleiben als deprecated Aliase erhalten; alle Direktreferenzen sollten Sie auf `PreventRequestForgery` umstellen. Achten Sie besonders auf Tests und Route-Definitionen, in denen die Middleware ausgeschlossen wird.

```php theme={null}
use Illuminate\Foundation\Http\Middleware\PreventRequestForgery;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;

// Laravel <= 12.x
->withoutMiddleware([VerifyCsrfToken::class]);

// Laravel >= 13.x
->withoutMiddleware([PreventRequestForgery::class]);
```

In der Middleware-Konfigurations-API ist `preventRequestForgery(...)` verfügbar.

***

### Cache

#### Cache-Präfix und Session-Cookie-Name

**Auswirkung: Niedrig**

Die Default-Präfixe für Cache und Redis-Keys verwenden nun Bindestrich-getrennte Suffixe. Der Default-Session-Cookie-Name nutzt `Str::snake(...)`.

Die meisten Anwendungen setzen diese Werte in ihrer Konfigurationsdatei explizit und sind nicht betroffen. Nur Anwendungen, die sich auf die Framework-Fallbacks verlassen, sind es.

```php theme={null}
// Laravel <= 12.x
Str::slug((string) env('APP_NAME', 'laravel'), '_').'_cache_';
Str::slug((string) env('APP_NAME', 'laravel'), '_').'_database_';
Str::slug((string) env('APP_NAME', 'laravel'), '_').'_session';

// Laravel >= 13.x
Str::slug((string) env('APP_NAME', 'laravel')).'-cache-';
Str::slug((string) env('APP_NAME', 'laravel')).'-database-';
Str::snake((string) env('APP_NAME', 'laravel')).'_session';
```

Um das bisherige Verhalten beizubehalten, setzen Sie die Werte explizit in `.env`.

```ini theme={null}
CACHE_PREFIX=myapp_cache_
REDIS_PREFIX=myapp_database_
SESSION_COOKIE=myapp_session
```

#### Cache-Einstellung `serializable_classes`

**Auswirkung: Mittel**

Der `cache`-Default-Konfiguration wurde `serializable_classes` mit dem Default `false` hinzugefügt. Damit werden PHP-Deserialisierungs-Gadget-Chain-Angriffe im Fall eines geleakten `APP_KEY` verhindert.

Wenn Ihre Anwendung PHP-Objekte im Cache ablegt, führen Sie die zu erlaubenden Klassen explizit auf.

```php theme={null}
// config/cache.php
'serializable_classes' => [
    App\Data\CachedDashboardStats::class,
    App\Support\CachedPricingSnapshot::class,
],
```

Wenn Sie zuvor beliebige Cache-Objekte deserialisiert haben, wechseln Sie auf eine explizite Allow-List oder auf Nicht-Objekt-Cache-Payloads (z. B. Arrays).

#### Session-Einstellung `serialization`

**Auswirkung: Mittel**

Im Skeleton (`laravel/laravel`) von Laravel 13 ist in `config/session.php` `'serialization' => 'json'` ergänzt. Der Framework-interne Default bleibt jedoch `php`.

<Warning>
  Wenn Sie mit KI-Tools die Skeleton-Änderungen unverändert übernehmen, kann `'serialization' => 'json'` in `config/session.php` gesetzt werden. Da dies das Serialisierungsverfahren der Session umschaltet, kann es in Anwendungen zu Fehlern führen, die PHP-Objekte in der Session speichern.
</Warning>

Der offizielle Upgrade-Guide erwähnt diese Änderung nicht. Vermutlich ist damit gemeint, dass sie **nicht zwingend übernommen werden muss**. Bei Laravel-Upgrades von einer Version zur nächsten gibt es gelegentlich Änderungen, die keine Auswirkung haben und daher im Guide fehlen. Wenn man Jahre später upgradet und keine Information findet, wird es schwierig – deshalb sind inoffizielle Aufzeichnungen wertvoll.

Um das Verhalten wie in Laravel 12 zu erhalten, setzen Sie `'serialization' => 'php'` explizit.

```php theme={null}
// config/session.php
'serialization' => 'php',
```

Wollen Sie die JSON-Serialisierung aktivieren, stellen Sie vorab sicher, dass keine PHP-Objekte in der Session gespeichert werden.

***

### Container

#### `Container::call` und nullable Klassen-Defaults

**Auswirkung: Niedrig**

`Container::call` berücksichtigt nun die Default-Werte nullable Klassenparameter, wenn keine Bindung existiert (analog zum Verhalten für die Konstruktorinjektion aus Laravel 12).

```php theme={null}
$container->call(function (?Carbon $date = null) {
    return $date;
});

// Laravel <= 12.x: liefert eine Carbon-Instanz
// Laravel >= 13.x: liefert null
```

***

### Datenbank

#### MySQL-`DELETE`-Queries

**Auswirkung: Niedrig**

Laravel kompiliert im MySQL-Grammar nun vollständige `DELETE ... JOIN`-Queries inklusive `ORDER BY` und `LIMIT`.

In früheren Versionen konnten diese Klauseln bei DELETEs mit JOIN ignoriert werden. In Laravel 13 sind sie im generierten SQL enthalten. In Datenbank-Engines, die diese Syntax nicht unterstützen, kann es zu `QueryException` kommen.

***

### Eloquent

#### Benennung polymorpher Pivot-Tabellen

**Auswirkung: Niedrig**

Beim Ableiten des Tabellennamens für polymorphe Pivot-Modelle mit einer eigenen Pivot-Klasse erzeugt Laravel nun einen Pluralnamen.

Wenn Sie sich auf den bisherigen Singular-Namen verlassen, setzen Sie den Tabellennamen im Pivot-Modell explizit.

```php theme={null}
class RoleUser extends MorphPivot
{
    protected $table = 'role_user'; // explizit setzen
}
```

#### Serialisierung von Model-Collections

**Auswirkung: Niedrig**

Beim Serialisieren und Wiederherstellen von Eloquent-Model-Collections (etwa bei in Queues gespeicherten Jobs) werden nun eager-geladene Relationen wieder an die Modelle gehängt.

Code, der sich auf das Fehlen dieser Relationen nach der Deserialisierung verlässt, benötigt Anpassungen.

***

### Queue

#### Exception-Payload im Event `JobAttempted`

**Auswirkung: Niedrig**

Das Event `Illuminate\Queue\Events\JobAttempted` gibt nun statt einer boolean-Property `$exceptionOccurred` das Exception-Objekt (oder `null`) über `$exception` frei.

```php theme={null}
// Laravel <= 12.x
if ($event->exceptionOccurred) {
    // Es ist eine Exception aufgetreten
}

// Laravel >= 13.x
if ($event->exception !== null) {
    // Es ist eine Exception aufgetreten
    $exception = $event->exception;
}
```

#### Umbenennung von Properties im Event `QueueBusy`

**Auswirkung: Niedrig**

Die Property `$connection` des Events `Illuminate\Queue\Events\QueueBusy` wurde zur Vereinheitlichung mit anderen Queue-Events in `$connectionName` umbenannt.

```php theme={null}
// Laravel <= 12.x
$event->connection;

// Laravel >= 13.x
$event->connectionName;
```

***

### Routing

#### Priorität registrierter Domain-Routen

**Auswirkung: Niedrig**

Routen mit expliziter Domain haben beim Matching nun Vorrang vor Routen ohne Domain.

Damit funktionieren Catch-All-Subdomain-Routen konsistent, auch wenn zuvor eine Nicht-Domain-Route registriert wurde.

***

### Support

#### Binding von Manager-`extend`-Callbacks

**Auswirkung: Niedrig**

Über `extend` registrierte Custom-Driver-Closures eines Managers werden nun an die Manager-Instanz gebunden.

Wenn in diesen Callbacks bisher `$this` auf ein anderes Objekt zeigte (etwa den Service Provider), verschieben Sie den Wert per `use (...)` in den Closure-Scope.

```php theme={null}
// Laravel <= 12.x
Manager::extend('custom', function ($app) {
    return $this->createCustomDriver($app); // $this ist der Service Provider
});

// Laravel >= 13.x
$provider = $this;
Manager::extend('custom', function ($app) use ($provider) {
    return $provider->createCustomDriver($app);
});
```

#### Reset der `Str`-Factory zwischen Tests

**Auswirkung: Niedrig**

Laravel setzt beim Test-Teardown Custom `Str`-Factories zurück.

Wenn Sie sich darauf verlassen haben, dass eine benutzerdefinierte UUID-/ULID-/Random-String-Factory über Testmethoden hinweg bestehen bleibt, konfigurieren Sie sie in jedem betreffenden Test oder Setup-Hook.

***

### Views

#### View-Namen der Bootstrap-Paginierung

**Auswirkung: Niedrig**

Die internen Paginierungs-View-Namen für Bootstrap 3 wurden explizit gemacht.

```php theme={null}
// Laravel <= 12.x
pagination::default
pagination::simple-default

// Laravel >= 13.x
pagination::bootstrap-3
pagination::simple-bootstrap-3
```

Wenn Sie die alten View-Namen direkt referenzieren, aktualisieren Sie sie.

***

## Deprecated Features

| Feature                            | Alternative                  |
| ---------------------------------- | ---------------------------- |
| Middleware `VerifyCsrfToken`       | `PreventRequestForgery`      |
| Middleware `ValidateCsrfToken`     | `PreventRequestForgery`      |
| `JobAttempted::$exceptionOccurred` | `JobAttempted::$exception`   |
| `QueueBusy::$connection`           | `QueueBusy::$connectionName` |

***

## Ergänzungen bei den Contracts

**Auswirkung: Sehr niedrig**

Nur relevant, wenn Sie eigene Implementierungen der Contracts pflegen.

### Contract `Dispatcher`

Der Contract `Illuminate\Contracts\Bus\Dispatcher` erhielt die Methode `dispatchAfterResponse($command, $handler = null)`.

### Contract `ResponseFactory`

Der Contract `Illuminate\Contracts\Routing\ResponseFactory` erhielt die Signatur `eventStream`.

### Contract `MustVerifyEmail`

Der Contract `Illuminate\Contracts\Auth\MustVerifyEmail` erhielt die Methode `markEmailAsUnverified()`.

### Contract `Queue`

Der Contract `Illuminate\Contracts\Queue\Queue` erhielt folgende Methoden zur Größenprüfung der Queue (zuvor nur im DocBlock deklariert).

* `pendingSize`
* `delayedSize`
* `reservedSize`
* `creationTimeOfOldestPendingJob`

### Contracts `Store` / `Repository`

An den Cache-Contracts wurde die Methode `touch` zur TTL-Verlängerung ergänzt.

```php theme={null}
// Illuminate\Contracts\Cache\Store
public function touch($key, $seconds);
```

***

## Highlights neuer Features

### KI-gestütztes Upgrade (Laravel Boost)

Laravel Boost ist der offizielle MCP-Server. In Verbindung mit KI-Editoren automatisieren Sie das Upgrade teilweise über `/upgrade-laravel-v13`.

### Origin-Prüfung per `Sec-Fetch-Site`

Die Middleware `PreventRequestForgery` prüft zusätzlich per `Sec-Fetch-Site` den Origin und stärkt damit den CSRF-Schutz.

### Sichere Cache-Deserialisierung

Über `serializable_classes` werden nur zugelassene Klassen deserialisiert. Die Sicherheit gegen PHP-Deserialisierungsangriffe verbessert sich.

### `eventStream` für SSE (Server-Sent Events)

Der Contract `ResponseFactory` erhält `eventStream`; die SSE-Unterstützung wurde verbessert.

### Bessere Sichtbarkeit von Queues

Mit `pendingSize`, `delayedSize`, `reservedSize` u. a. am `Queue`-Contract lassen sich Queue-Zustände granularer beobachten.

***

## Häufige Migrationsprobleme und Lösungen

### Problem: CSRF-Tests schlagen fehl

**Symptom:** Tests, die `VerifyCsrfToken` referenzieren, schlagen mit „Klasse nicht gefunden" fehl.

**Lösung:** Alle Referenzen auf `PreventRequestForgery` umstellen.

```php theme={null}
// Vorher
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
->withoutMiddleware([VerifyCsrfToken::class]);

// Nachher
use Illuminate\Foundation\Http\Middleware\PreventRequestForgery;
->withoutMiddleware([PreventRequestForgery::class]);
```

### Problem: Cache liefert keine Objekte zurück

**Symptom:** Aus dem Cache gelesene Daten sind `null` oder es wird eine `UnserializationFailedException` geworfen.

**Lösung:** Ergänzen Sie die verwendeten Klassen in `config/cache.php` unter `serializable_classes` oder wandeln Sie die zwischengespeicherten Werte in Arrays um.

```php theme={null}
'serializable_classes' => [
    App\Models\User::class,
    App\Data\SomeData::class,
],
```

### Problem: `JobAttempted`-Listener funktioniert nicht

**Symptom:** `$event->exceptionOccurred` ist `null` oder undefiniert.

**Lösung:** Auf `$event->exception !== null` umstellen.

```php theme={null}
// Vorher
if ($event->exceptionOccurred) { ... }

// Nachher
if ($event->exception !== null) { ... }
```

### Problem: Session wird ungültig

**Symptom:** Nach dem Upgrade werden Nutzer ausgeloggt.

**Lösung:** Der Default-Session-Cookie-Name hat sich geändert. Setzen Sie in `.env` `SESSION_COOKIE` explizit auf den bisherigen Wert.

```ini theme={null}
SESSION_COOKIE=laravel_session
```

### Problem: Cache-Keys werden nicht gefunden

**Symptom:** Nach dem Upgrade steigt die Zahl der Cache-Misses.

**Lösung:** Das Cache-Präfix hat sich geändert. Setzen Sie `CACHE_PREFIX` in `.env` oder leeren Sie den Cache.

```shell theme={null}
php artisan cache:clear
```

***

## Referenzen

* [Offizieller Upgrade-Guide (Englisch)](https://laravel.com/docs/13.x/upgrade)
* [Diff im Repository laravel/laravel (12.x → 13.x)](https://github.com/laravel/laravel/compare/12.x...13.x)
* [Laravel Shift](https://laravelshift.com) – Community-Dienst zur Upgrade-Automatisierung
* [Laravel Boost](https://github.com/laravel/boost) – MCP-Server für KI-gestützte Upgrades


## Related topics

- [Übersicht der neuen Features in Laravel 13](/de/blog/laravel-13-new-features.md)
- [Upgrade-Anleitung von Laravel 11 auf 12](/de/blog/upgrade-11-to-12.md)
- [Upgrade von Laravel 8 auf 9](/de/blog/upgrade-8-to-9.md)
- [Upgrade von Laravel 9 auf 10](/de/blog/upgrade-9-to-10.md)
- [Upgrade von Laravel 10 auf 11](/de/blog/upgrade-10-to-11.md)
