Zum Hauptinhalt springen

Einleitung

Laravel 13 wurde im März 2026 veröffentlicht. Dieser Leitfaden beschreibt die Upgrade-Schritte von Laravel 12.x auf 13.x.
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.

KI-gestütztes Upgrade

Sie können das Upgrade auch mit 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.
Prompt
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.
{
  "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.
{
  "require": {
    "laravel/boost": "^2.0"
  }
}
Installieren Sie anschließend die Abhängigkeiten:
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:
composer global update laravel/installer
Wenn Sie die Bundled-Version von Laravel Herd 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.
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

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.
// 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.
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.
// 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.
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.
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.
// 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).
$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.
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.
// 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.
// 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.
// 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.
// 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

FeatureAlternative
Middleware VerifyCsrfTokenPreventRequestForgery
Middleware ValidateCsrfTokenPreventRequestForgery
JobAttempted::$exceptionOccurredJobAttempted::$exception
QueueBusy::$connectionQueueBusy::$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.
// 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.
// 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.
'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.
// 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.
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.
php artisan cache:clear

Referenzen

Zuletzt geändert am 13. Juli 2026