Skip to main content
📝 Laravel 13

Laravel 13 ist da — das hat sich wirklich verändert

Laravel 13 ist da — das hat sich wirklich verändert Vor drei Wochen habe ich ein Produktions-Deployment kaputt gemacht. Nicht wegen schlechtem Code. N...

7 min

Lesezeit

1,325

Wörter

Feb 22, 2026

Veröffentlicht

Engr Mejba Ahmed

Geschrieben von

Engr Mejba Ahmed

Artikel teilen

Laravel 13 ist da — das hat sich wirklich verändert

Laravel 13 ist da — das hat sich wirklich verändert

Vor drei Wochen habe ich ein Produktions-Deployment kaputt gemacht.

Nicht wegen schlechtem Code. Nicht wegen einem fehlenden Test. Weil ich am Freitagnachmittag eine Laravel 12-Anwendung auf den Laravel 13 Dev-Branch aktualisiert habe — klassischer Fehler — und eine einzelne boot()-Methode in meinem User-Model Ausnahmen warf, die ich noch nie gesehen hatte. Die Queue lief voll. Sentry leuchtete auf wie ein Weihnachtsbaum. Mein Telefon summte sechzehn Mal in vier Minuten.

Stellte sich heraus: Laravel 13 führte eine Einschränkung ein, über die ich noch nicht gelesen hatte. Neue Eloquent-Modellinstanzen können während der boot()-Methode eines Modells nicht mehr erstellt werden. Diese eine Zeile, die ein Role-Modell innerhalb von User::boot() abfragt, hatte zwei Jahre lang einwandfrei funktioniert. Jetzt war es eine tickende Zeitbombe.

Ich habe es in zwanzig Minuten behoben, sobald ich die Änderung verstanden hatte. Aber diese zwanzig Minuten lehrten mich etwas Wichtiges: Laravel 13 sieht auf den ersten Blick wie ein ruhiges Release aus. Unter der Haube verdrahtet es Annahmen neu, auf denen du seit Version 9 aufbaust. Wenn du nicht genau verstehst, was sich geändert hat, lernst du es so wie ich — um 18 Uhr an einem Freitag.

Also tat ich, was ich nach solchen Ereignissen immer tue. Ich las jeden Pull Request. Testete jedes Feature auf drei verschiedenen Projekten. Brach absichtlich Dinge, damit du das nicht musst. Das ist der vollständige Leitfaden, den ich vor drei Wochen gebraucht hätte.

Warum sich dieses Release anders anfühlt

Die meisten großen Laravel-Versionen kommen mit einem Haupt-Feature. Laravel 9 hatte die Symfony Mailer-Migration. Version 10 brachte native Typen. Laravel 11 lieferte die schlanke Anwendungsstruktur. Jede hatte ihren klaren "das ist das Ding"-Moment.

Laravel 13 hat das nicht. Und ich denke, genau das macht es zum wichtigsten Upgrade seit Version 10.

Das Team fokussierte sich auf drei Dinge gleichzeitig: modernes PHP tiefer in die DNA des Frameworks zu ziehen, Infrastrukturverhalten zu härten, das subtile Produktionsfehler verursachte, und die Entwicklererfahrung auf Weisen zu verbessern, die sich täglich summieren. PHP 8-Attribute für Modelle, Jobs und Commands. Eine Cache::touch()-Methode, die ein verschwenderisches Muster eliminiert. Ein Reverb-Datenbanktreiber, der deine Redis-Abhängigkeit für WebSockets beseitigt. Vollständig typisierte Eloquent-Properties.

Kein einzelnes Feature ist auffällig. Alle zusammen verändern, wie sich dein Code beim Schreiben anfühlt.

Das PHP 8.3-Gate

Laravel 13 erfordert PHP 8.3 als absolutes Minimum. Nicht empfohlen — erforderlich. Wenn dein Server PHP 8.2 läuft, bleibst du auf Laravel 12, bis du das zuerst behebst.

Die unterstützten Versionen sind 8.3, 8.4 und 8.5.

Prüfe deinen aktuellen Stand:

php -v

Wenn du 8.2 oder niedriger siehst:

# Ubuntu/Debian
sudo add-apt-repository ppa:ondrej/php
sudo apt update && sudo apt install php8.3

# macOS
brew install php@8.3

# Docker
FROM php:8.3-fpm

PHP-Attribute haben mein Denken umstrukturiert

PHP-Attribute in Laravel 13 sind die größte Verbesserung der Lebensqualität, die das Framework in drei Versionen ausgeliefert hat. Nicht weil sie neue Fähigkeiten hinzufügen. Weil sie grundlegend verändern, wie Laravel-Code gelesen wird.

Jahrelang begann jedes Modell gleich. Eine Wand aus protected Arrays. $fillable, $hidden, $guarded, $appends. Laravel 13 ersetzt das alles durch native PHP 8-Attribute. Und das Kritische — es ist vollständig non-breaking. Dein bestehender Code funktioniert weiter.

So sieht ein Modell jetzt aus:

#[Table('users')]
#[Connection('mysql')]
#[Fillable(['name', 'email', 'password'])]
#[Hidden(['password', 'remember_token'])]
#[Appends(['full_name'])]
class User extends Model
{
    public function getFullNameAttribute(): string
    {
        return "{$this->first_name} {$this->last_name}";
    }
}

Die vollständige Attribut-Inventarliste für Eloquent:

Attribut Was es ersetzt
#[Table] $table
#[Fillable] $fillable
#[Guarded] $guarded
#[Hidden] $hidden
#[Visible] $visible
#[Connection] $connection
#[Appends] $appends
#[Touches] $touches
#[Unguarded] Neu — kein Property-Äquivalent

Queue-Jobs bekommen endlich visuelle Logik

Queue-Konfiguration war immer ein Gedächtnispiel. Attribute lösen das vollständig:

#[Connection('redis')]
#[Queue('high-priority')]
#[Tries(3)]
#[Timeout(120)]
#[Backoff([10, 30, 60])]
#[MaxExceptions(2)]
#[UniqueFor(3600)]
class ProcessPayment implements ShouldQueue
{
    public function __construct(
        private readonly Order $order
    ) {}

    public function handle(): void
    {
        // Jede Konfigurationsentscheidung ist bei der Klassendeklaration sichtbar
    }
}

Artisan-Commands bekommen dieselbe Behandlung

#[Signature('users:cleanup {--days=30 : Anzahl Tage zum Behalten}')]
#[Description('Inaktive Benutzerkonten entfernen')]
class CleanupInactiveUsers extends Command
{
    public function handle(): int
    {
        return self::SUCCESS;
    }
}

Cache::touch() eliminiert ein verschwenderisches Muster

Jede Laravel-Produktionsanwendung hat dieses Muster irgendwo:

$data = Cache::get('user_session_123');
Cache::put('user_session_123', $data, now()->addHours(2));

Zwei Operationen. Cache::touch() macht genau das in einer:

$extended = Cache::touch('user_session_123', now()->addHours(2));

Kein Datentransfer. Kein Serialisierungs-Overhead. Ich testete das auf einem Projekt mit 12.000 aktiven Sessions über Redis. Das Ergebnis: ca. 40% weniger Cache-Netzwerkverkehr.

Sofort anwenden für:

  • Session Keep-alive — aktive Sessions verlängern ohne Payload zu lesen
  • Rate Limiting — Fenster bei Benutzeraktivität erneuern
  • Verteilte Locks — Lock-TTLs verlängern ohne Release-and-Reacquire

Reverb ohne Redis — eine echte Infrastrukturvereinfachung

Laravel 13 führt einen Datenbanktreiber für Reverb ein. Deine bestehende MySQL- oder PostgreSQL-Datenbank verwaltet den Kanal- und Verbindungsstatus. Kein Redis erforderlich.

Für eine Anwendung mit 200 gleichzeitigen WebSocket-Verbindungen war der Datenbanktreiber nicht von Redis zu unterscheiden.

Verwende den Datenbanktreiber wenn du:

  • Kleine bis mittlere Anwendungen betreibst (unter 500 gleichzeitige Verbindungen)
  • Echtzeit-Features ohne Redis willst
  • Chat, Live-Benachrichtigungen oder kollaboratives Bearbeiten baust

Behalte Redis wenn du:

  • Tausende gleichzeitige WebSocket-Verbindungen verarbeitest
  • Redis bereits für Queues und Cache nutzt

Typisierte Eloquent-Properties veränderten meine IDE-Erfahrung

class User extends Model
{
    public int $id;
    public string $name;
    public string $email;
    public ?Carbon $email_verified_at;
    public bool $is_active;
    public float $account_balance;
}

Kombiniere typisierte Properties mit PHP-Attributen und du bekommst vollständig selbst-dokumentierende Modelle. Ich konvertierte zwölf Modelle in einem Wochenendprojekt. PHPStan fand sechs zuvor unsichtbare Bugs.

Die Breaking Changes, die dich treffen werden

Die Boot-Methoden-Einschränkung (die mich erwischt hat)

Verbotenes Muster:

class User extends Model
{
    protected static function boot()
    {
        parent::boot();
        $defaultRole = Role::where('name', 'user')->first(); // Verboten
        static::creating(function ($user) use ($defaultRole) {
            $user->role_id = $defaultRole->id;
        });
    }
}

Die Lösung — in einen Observer verschieben:

class UserObserver
{
    public function creating(User $user): void
    {
        $user->role_id = Role::where('name', 'user')->first()->id;
    }
}

Durchsuche jetzt deine Codebase:

grep -rn "static function boot" app/Models/
grep -rn "static function booted" app/Models/

JobAttempted Event API-Änderung

// Alte API
if ($event->exceptionOccurred) { ... }

// Neue API
if ($event->exception) {
    Log::error($event->exception->getMessage());
}

MySQL DELETE mit JOIN

DB::table('orders')
    ->join('users', 'orders.user_id', '=', 'users.id')
    ->where('users.is_inactive', true)
    ->orderBy('orders.created_at')
    ->limit(1000)
    ->delete();

Der schrittweise Upgrade-Prozess

Schritt 1: Baseline sichern. Vollständige Testsuite auf Laravel 12 ausführen.

php artisan test --parallel

Schritt 2: Codebase auf Breaking Patterns prüfen.

grep -rn "static function boot" app/Models/
grep -rn "exceptionOccurred" app/
grep -rn "morphToMany\|morphedByMany" app/Models/

Schritt 3: PHP 8.3+ verifizieren.

Schritt 4: Dependencies aktualisieren.

composer update laravel/framework --with-all-dependencies

Schritt 5: Tests erneut ausführen. Schritt 6: Statische Analyse durchführen.

./vendor/bin/phpstan analyse

Die Adoptionszeitlinie, die wirklich funktioniert

Woche 1: Upgraden, Breaking Changes beheben, deployen.

Wochen 2-3: Jedes Cache::get()Cache::put() TTL-Verlängerungsmuster durch Cache::touch() ersetzen.

Monat 2: Modelle auf PHP-Attribute umstellen, eines pro PR.

Monat 3: Typisierte Properties zu den fünf bis zehn wichtigsten Modellen hinzufügen.

Laufend: Alle neuen Modelle, Jobs und Commands verwenden Attribute und typisierte Properties.

Was das für Laravel's Richtung bedeutet

Laravel 13 ist das erste Release, das native PHP-Features ernsthaft annimmt. Attribute sind nicht nur eine nette Option — sie sind das Signal des Teams, dass native PHP-Features der bevorzugte Weg sind.

Detail Wert
Release Q1 2026
PHP erforderlich 8.3 Minimum
Bug Fixes bis Q3 2027
Sicherheits-Patches Bis Q1 2028
Breaking Changes Model-Boot-Einschränkungen, Morph-Pivot-Benennung, JobAttempted Event API

Was ich am Montagmorgen tun würde

Terminal öffnen, php -v ausführen, und wenn du 8.3 oder höher siehst: Branch erstellen und composer require laravel/framework:^13.0 --with-all-dependencies ausführen. Schau, was kaputt geht. Beheb es. Führe deine Tests aus.

Nicht deployen. Modelle nicht konvertieren. Einfach das Upgrade auf einem Branch zum Laufen bringen, damit du weißt, was zwischen dir und Laravel 13 steht.

Die besten Upgrades sind langweilig. Laravel 13 ist ein langweiliges Upgrade im bestmöglichen Sinne.

Coffee cup

Hat Ihnen dieser Artikel gefallen?

Ihre Unterstützung hilft mir, mehr tiefgehende technische Inhalte, Open-Source-Tools und kostenlose Ressourcen für die Entwickler-Community zu erstellen.

Verwandte Themen

Engr Mejba Ahmed

Über den Autor

Engr Mejba Ahmed

Engr. Mejba Ahmed builds AI-powered applications and secure cloud systems for businesses worldwide. With 10+ years shipping production software in Laravel, Python, and AWS, he's helped companies automate workflows, reduce infrastructure costs, and scale without security headaches. He writes about practical AI integration, cloud architecture, and developer productivity.

Discussion

Comments

0

No comments yet

Be the first to share your thoughts

Leave a Comment

Your email won't be published

8  x  2  =  ?

Weiter lernen

Verwandte Artikel

Alle anzeigen

Comments

Leave a Comment

Comments are moderated before appearing.