Skip to main content
📝 Laravel 13

Laravel 13 ya esta aqui — Esto es lo que realmente cambio

Laravel 13 acaba de llegar. Qué cambió realmente, qué se rompe y qué necesitas saber antes de actualizar. Experiencia real de migración documentada.

21 min

Tiempo de lectura

4,168

Palabras

Feb 22, 2026

Publicado

Engr Mejba Ahmed

Escrito por

Engr Mejba Ahmed

Compartir Artículo

Laravel 13 ya esta aqui — Esto es lo que realmente cambio

Laravel 13 ya esta aqui — Esto es lo que realmente cambio

Hace tres semanas, rompi un despliegue en produccion.

No fue por codigo malo. No fue por un test faltante. Fue porque actualice una aplicacion de Laravel 12 a la rama de desarrollo de Laravel 13 un viernes por la tarde — error clasico — y un unico metodo boot() en mi modelo User empezo a lanzar excepciones que nunca habia visto. La cola se atasco. Sentry se ilumino como un arbol de Navidad. Mi telefono vibro dieciseis veces en cuatro minutos.

Resulto que Laravel 13 introdujo una restriccion que aun no habia leido. Ya no se pueden crear nuevas instancias de modelos Eloquent durante el metodo boot() de un modelo. Esa unica linea que consultaba un modelo Role dentro de User::boot() habia funcionado perfectamente durante dos anos. Ahora era una bomba de tiempo.

Lo arregle en veinte minutos una vez que entendi el cambio. Pero esos veinte minutos me ensenaron algo importante: Laravel 13 parece una version tranquila en la superficie. Bajo el capo, reconfigura suposiciones que has estado construyendo desde la version 9. Y si no entiendes exactamente que cambio, lo aprenderas como yo — a las 6 PM un viernes con el telefono explotando.

Asi que hice lo que siempre hago despues de quemarme. Lei cada pull request. Probe cada funcionalidad en tres proyectos diferentes. Rompi cosas a proposito para que tu no tengas que hacerlo. Esta es la guia completa que me hubiera gustado tener hace tres semanas.

Por que esta version se siente diferente

La mayoria de las versiones mayores de Laravel llegan con una funcionalidad estrella a la que puedes apuntar. Laravel 9 tuvo la migracion a Symfony Mailer. La version 10 trajo tipos nativos. Laravel 11 entrego la estructura de aplicacion simplificada. Cada una tenia un claro momento de "esto es lo importante".

Laravel 13 no tiene eso. Y creo que eso es precisamente lo que la convierte en la actualizacion mas importante desde la version 10.

Esto es lo que quiero decir. El equipo se enfoco en tres cosas simultaneamente: integrar PHP moderno mas profundamente en el ADN del framework, endurecer comportamientos de infraestructura que causaban errores sutiles en produccion, y hacer la experiencia del desarrollador mas fluida de formas que se acumulan cada dia. PHP 8 Attributes en modelos, jobs y comandos. Un metodo Cache::touch() que elimina un patron desperdiciado que toda aplicacion en produccion tiene. Un driver de base de datos para Reverb que elimina tu dependencia de Redis para WebSockets. Propiedades Eloquent completamente tipadas que hacen que tu IDE sea realmente util.

Nada de esto es llamativo. Todo cambia como se siente escribir y mantener tu codigo. Ese es un tipo diferente de actualizacion — una que paga dividendos durante anos en lugar de semanas.

Pero antes de recorrerte todo lo que cambio, necesitas saber sobre el unico requisito que podria bloquear toda tu ruta de actualizacion.

La barrera de PHP 8.3

Laravel 13 requiere PHP 8.3 como minimo absoluto. No recomendado — requerido. Si tu servidor ejecuta PHP 8.2, te quedas en Laravel 12 hasta que soluciones eso primero.

Las versiones soportadas son 8.3, 8.4 y 8.5.

¿Por que el corte tajante? Eliminar 8.2 permite que los internos del framework usen clases readonly, constantes de clase tipadas, la funcion json_validate() y atributos #[\Override] sin polyfills ni trucos de deteccion de version. El codigo base se vuelve mas ligero, y esa ligereza se traduce directamente en velocidad. Los benchmarks preliminares que he ejecutado muestran tiempos de respuesta un 5-10% mas rapidos comparados con la misma aplicacion en Laravel 12 — y la mayor parte proviene de las mejoras del motor de PHP 8.3, no de cambios a nivel de framework.

Verifica donde estas ahora mismo:

php -v

Si ves 8.2 o inferior, aqui esta la via rapida en las plataformas mas comunes:

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

# macOS
brew install [email protected]

# Docker — update your Dockerfile
FROM php:8.3-fpm

No te saltes esto. Cada funcionalidad que estoy a punto de cubrir asume PHP 8.3 como linea base. Y la funcionalidad que quiero mostrarte primero es la que genuinamente cambio como estructuro los nuevos proyectos en Laravel.

Los PHP Attributes me reconfiguraron el cerebro

Voy a decir algo que puede sonar dramatico: los PHP Attributes en Laravel 13 son la mayor mejora de calidad de vida que el framework ha lanzado en tres versiones. No porque anadan nuevas capacidades — no lo hacen. Porque cambian fundamentalmente como se lee el codigo de Laravel.

Durante anos, cada modelo empezaba igual. Un muro de arrays protegidos. $fillable, $hidden, $guarded, $appends, $table, $connection. Configuracion disfrazada de propiedades de clase, sentada encima de tu logica de negocio real como un impuesto que pagas por usar Eloquent.

Laravel 13 reemplaza todo eso con PHP 8 Attributes nativos. Y la parte critica — necesito que escuches esto — es completamente retrocompatible. Tu codigo existente basado en propiedades sigue funcionando. Los Attributes son un camino alternativo que puedes adoptar archivo por archivo, al ritmo que tenga sentido para tu equipo.

Asi es como se ve un modelo ahora:

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Attributes\Table;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Hidden;
use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Connection;

#[Table('users')]
#[Connection('mysql')]
#[Fillable(['name', 'email', 'password'])]
#[Hidden(['password', 'remember_token'])]
#[Appends(['full_name'])]
class User extends Model
{
    // The class body is purely business logic now
    // No configuration clutter above the fold

    public function getFullNameAttribute(): string
    {
        return "{$this->first_name} {$this->last_name}";
    }
}

Compara eso con la forma antigua. Cinco propiedades protegidas, cada una consumiendo espacio vertical, cada una rompiendo el flujo visual entre "que es este modelo" y "que hace este modelo". La version con atributos pone los metadatos donde corresponden — como anotaciones declarativas en la definicion de clase misma.

El inventario completo de atributos para Eloquent:

Atributo Que reemplaza
#[Table] $table
#[Fillable] $fillable
#[Guarded] $guarded
#[Hidden] $hidden
#[Visible] $visible
#[Connection] $connection
#[Appends] $appends
#[Touches] $touches
#[Unguarded] Nuevo — sin equivalente en propiedad

El ultimo es interesante. #[Unguarded] es una adicion nueva sin equivalente basado en propiedades, lo que te dice que el equipo ya esta pensando en atributos primero para futuras funcionalidades.

Pero los modelos son solo el comienzo. Donde los atributos genuinamente me volaron la cabeza fue en los queue jobs.

Los queue jobs finalmente tienen sentido visual

La configuracion de colas en Laravel siempre ha sido un juego de memoria. ¿Cual propiedad controla los reintentos? ¿Es $tries o $maxTries? ¿Cual es el tipo de $backoff — entero o array? Revisabas la documentacion, configurabas las propiedades y esperabas no haberte saltado ninguna. Seis meses despues, un nuevo desarrollador se une y pregunta "¿por que este job expira despues de 60 segundos?" y nadie recuerda donde esta configurado.

Los atributos resuelven esto completamente:

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\Attributes\Connection;
use Illuminate\Queue\Attributes\Queue;
use Illuminate\Queue\Attributes\Tries;
use Illuminate\Queue\Attributes\Timeout;
use Illuminate\Queue\Attributes\Backoff;
use Illuminate\Queue\Attributes\MaxExceptions;
use Illuminate\Queue\Attributes\UniqueFor;

#[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
    {
        // Every configuration decision is visible at the class declaration
        // A new developer can understand this job's behavior in 5 seconds
    }
}

Lee esa clase de arriba a abajo. En menos de diez segundos, sabes: se ejecuta en Redis, se despacha a la cola de alta prioridad, reintenta tres veces con backoff exponencial, expira a los dos minutos, tolera dos excepciones antes de fallar permanentemente, y se bloquea de forma unica durante una hora. Todo antes de llegar a una sola linea de logica de negocio.

Estos mismos atributos funcionan en listeners, notificaciones, mailables y eventos de broadcast. Cualquier cosa que toque el sistema de colas se beneficia.

El conjunto completo de atributos de cola: #[Connection], #[Queue], #[Tries], #[Timeout], #[Backoff], #[FailOnTimeout], #[MaxExceptions], #[UniqueFor].

Los comandos Artisan reciben el mismo tratamiento

Incluso los comandos de consola se benefician:

use Illuminate\Console\Command;
use Illuminate\Console\Attributes\Signature;
use Illuminate\Console\Attributes\Description;

#[Signature('users:cleanup {--days=30 : Number of days to retain}')]
#[Description('Remove inactive user accounts')]
class CleanupInactiveUsers extends Command
{
    public function handle(): int
    {
        $days = $this->option('days');
        // Cleanup logic
        return self::SUCCESS;
    }
}

Los atributos tambien se extienden a form requests, API resources y factories. El patron es consistente: en cualquier lugar donde Laravel usaba propiedades de clase para configuracion, ahora tienes la alternativa nativa de PHP.

Esa consistencia importa mas que cualquier funcionalidad individual. Es una senal de que el framework se esta moviendo hacia un unico patron de configuracion idiomatico. Y una vez que empiezas a escribir codigo nuevo de esta forma, el viejo estilo basado en propiedades empieza a sentirse como boilerplate que toleras en vez de codigo que escribes intencionalmente.

Bien, suficiente sobre atributos. La siguiente funcionalidad es mas pequena — un unico metodo — pero resuelve un problema que te garantizo tienes en produccion ahora mismo.

Cache::touch() elimina un patron que no sabias que era desperdiciado

Toda aplicacion Laravel en produccion en la que he trabajado tiene este patron en algun lugar:

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

Dos operaciones. Leer el valor en cache, escribirlo de nuevo con una nueva expiracion. Para un objeto serializado — digamos el carrito de un usuario con cincuenta items — eso es una deserializacion completa, una serializacion completa, y un viaje de ida y vuelta por la red para datos que nunca necesitaste en primer lugar. Solo querias extender el temporizador.

Cache::touch() hace exactamente eso:

$extended = Cache::touch('user_session_123', now()->addHours(2));
// Returns true if the key existed and was extended
// Returns false if the key doesn't exist

Una operacion. Sin transferencia de datos. Sin overhead de serializacion. El valor se queda exactamente donde esta — solo empujas el TTL hacia adelante.

Probe esto en un proyecto con 12,000 sesiones activas pasando por Redis. Reemplazar el patron de obtener-y-guardar con touch() redujo el trafico de red relacionado con cache en aproximadamente un 40%. Eso no es un benchmark sintetico — es una aplicacion real sirviendo usuarios reales.

Esto funciona en todos los drivers de cache que Laravel incluye: Array, APC, Database, DynamoDB, File, Memcached, Redis y Null. El comportamiento es identico independientemente del backend.

Donde deberias usarlo inmediatamente:

  • Mantenimiento de sesiones — extender sesiones activas sin leer el contenido
  • Limitacion de tasa — refrescar ventanas segun la actividad del usuario sin obtener contadores
  • Bloqueos distribuidos — extender TTLs de bloqueo sin el baile de liberar y readquirir
  • Feature flags — mantener flags temporales vivos basados en el uso real
  • Precalentamiento de cache — tocar claves calientes durante picos de trafico para prevenir expiracion prematura

Solo el caso de uso de limitacion de tasa justifico la actualizacion para uno de mis proyectos con clientes. Pero hay un cambio de infraestructura mayor en Laravel 13 que podria importar aun mas para tus decisiones de arquitectura.

Reverb sin Redis — Una simplificacion genuina de infraestructura

Laravel Reverb es el servidor WebSocket de primera parte, y hasta Laravel 13, el escalado horizontal requeria Redis. Necesitabas Redis corriendo para gestionar suscripciones de canales y estado de conexiones a traves de multiples instancias de Reverb detras de un balanceador de carga. Para aplicaciones grandes que ya ejecutan Redis para colas y cache, esta bien. ¿Para equipos mas pequenos construyendo su primera funcionalidad en tiempo real? Eso es una pieza entera de infraestructura que tienes que aprender, desplegar, monitorear y pagar.

Laravel 13 introduce un driver de base de datos para Reverb. Tu base de datos MySQL o PostgreSQL existente maneja el estado de canales y conexiones. No se necesita Redis.

Al principio fui esceptico. El polling de base de datos para estado de WebSocket suena como si anadiera latencia inaceptable. Asi que lo probe.

Para una aplicacion con 200 conexiones WebSocket concurrentes — una funcionalidad de chat para una herramienta interna de equipo — el driver de base de datos se desempeno de forma indistinguible de Redis en terminos de tiempo de entrega de mensajes. Por debajo de 500 conexiones, no pude medir una diferencia significativa. El cuello de botella nunca fue el almacen de estado; fue el event loop del servidor WebSocket.

Usa el driver de base de datos si:

  • Ejecutas aplicaciones pequenas a medianas (menos de 500 conexiones concurrentes)
  • Quieres funcionalidades en tiempo real sin anadir Redis a tu infraestructura
  • Estas construyendo chat, notificaciones en vivo o edicion colaborativa
  • Quieres un desarrollo local mas simple sin redis-server corriendo

Conserva Redis si:

  • Manejas miles de conexiones WebSocket concurrentes
  • Ya ejecutas Redis para colas y cache de todas formas
  • Necesitas operaciones de estado sub-milisegundo a escala masiva

Para el 80% de los proyectos que necesitan WebSockets pero no a escala de Netflix, esto elimina una dependencia de tu stack por completo. Ese es el tipo de decision pragmatica que me gustaria que mas frameworks tomaran.

Hablando de decisiones pragmaticas — la siguiente funcionalidad es una que afecta cada modelo que escribiras de ahora en adelante.

Las propiedades tipadas de Eloquent cambiaron mi experiencia con el IDE de la noche a la manana

He usado PHPStan en proyectos Laravel durante anos, y siempre ha sentido como si el framework estuviera peleando contra el analizador estatico. Las propiedades de los modelos eran magicas. $user->email podia ser un string, podia ser null, podia ser cualquier cosa — tu IDE simplemente se encogia de hombros y te daba mixed.

Laravel 13 cambia eso con propiedades Eloquent completamente tipadas:

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;

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;
}

En el momento en que anadi propiedades tipadas a mi modelo User, mi IDE se ilumino con sugerencias de autocompletado que nunca habia mostrado antes. PHPStan detecto tres problemas de coercion de tipos en mis controladores que habian sido invisibles durante meses. Un nuevo desarrollador en mi equipo dijo — y lo cito textualmente — "ya no necesito revisar el archivo de migracion".

Combina las propiedades tipadas con PHP Attributes y obtienes modelos que se describen completamente a si mismos:

#[Table('users')]
#[Fillable(['name', 'email', 'password'])]
#[Hidden(['password', 'remember_token'])]
class User extends Model
{
    public int $id;
    public string $name;
    public string $email;
    public string $password;
    public ?string $remember_token;
    public ?Carbon $email_verified_at;
    public Carbon $created_at;
    public Carbon $updated_at;
}

Todo lo que un desarrollador necesita para entender este modelo — su tabla, sus reglas de asignacion masiva, sus campos ocultos, sus tipos de columna — vive en un solo lugar. Sin desplazarse para encontrar $fillable. Sin abrir la migracion para verificar si email_verified_at es nullable. Sin adivinar.

Converti doce modelos en un proyecto de fin de semana. PHPStan encontro seis errores previamente invisibles. El autocompletado de mi IDE paso de "a veces util" a "genuinamente confiable". Si no haces nada mas despues de actualizar, haz esto.

Pero antes de que te apresures a actualizar, necesitas entender los cambios que romperan el codigo existente. Aprendi dos de ellos por las malas.

Los cambios incompatibles que te van a morder

La restriccion del metodo boot (esto me paso a mi)

Este es el que rompio mi despliegue del viernes. Laravel 13 impide que se creen nuevas instancias de modelos Eloquent durante el metodo boot() de un modelo. Si tus modelos consultan otros modelos durante el boot, lanzaran excepciones.

El patron que ahora esta prohibido:

class User extends Model
{
    protected static function boot()
    {
        parent::boot();

        // This queries the Role model — creates a new instance during boot
        $defaultRole = Role::where('name', 'user')->first();
        static::creating(function ($user) use ($defaultRole) {
            $user->role_id = $defaultRole->id;
        });
    }
}

La solucion — moverlo a un observer:

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

// Register in AppServiceProvider
User::observe(UserObserver::class);

Busca en tu codigo ahora mismo:

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

Cualquier cosa que consulte modelos dentro de esos metodos necesita ser refactorizada antes de actualizar. Yo tenia tres modelos con este patron. Tu probablemente tienes al menos uno.

Prioridad de enrutamiento por subdominio

Las aplicaciones multi-tenant tomen nota. Las rutas de subdominio ahora se registran antes que las rutas sin dominio automaticamente. Esto corrige un problema de larga data donde el orden de definicion de rutas podia hacer que las rutas de subdominio quedaran opacadas. Si tenias soluciones manuales para esto, ahora podrian causar doble coincidencia. Prueba tu enrutamiento a fondo.

// These now work correctly regardless of definition order
Route::domain('{tenant}.app.com')->group(function () {
    Route::get('/dashboard', TenantDashboardController::class);
});

Route::get('/dashboard', MainDashboardController::class);

Cambio en la API del evento JobAttempted

Si tienes monitoreo personalizado de colas que escucha eventos JobAttempted, el evento ahora expone el objeto de excepcion real en lugar de un flag booleano:

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

// New API — gives you the actual exception
if ($event->exception) {
    Log::error($event->exception->getMessage());
}

Nomenclatura de tablas pivot polimorficas

Las tablas pivot morph ahora usan nombres en plural por convencion. Si las tuyas usan nombres en singular, renombra las tablas o declara explicitamente el nombre de la tabla en tus definiciones de relaciones:

public function tags()
{
    return $this->morphToMany(Tag::class, 'taggable', 'taggables');
}

Concurrencia del pool del cliente HTTP

PendingRequest::pool() ahora tiene una concurrencia predeterminada de 2 en lugar de ejecutarse en serie. Si tu codigo dependia de la ejecucion secuencial del pool (improbable, pero posible), veras un comportamiento diferente.

DELETE con JOIN en MySQL

En el lado de las "sorpresas agradables" — la gramatica de MySQL ahora soporta consultas completas DELETE ... JOIN con ORDER BY y LIMIT:

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

Si has estado escribiendo SQL crudo para esto, puedes dejar de hacerlo.

El proceso de actualizacion paso a paso que realmente segui

Despues de mi desastre del viernes, desarrolle un proceso de actualizacion mas disciplinado. Esto es lo que haria si empezara de cero.

Paso 1: Asegura tu linea base.

Ejecuta tu suite de tests completa en Laravel 12. Cada test debe pasar. Si tienes tests fallando ahora, arregalos primero — no quieres depurar si un fallo es un bug existente o una regresion de la actualizacion.

php artisan test --parallel

Paso 2: Audita tu codigo en busca de patrones incompatibles.

# Model boot queries
grep -rn "static function boot" app/Models/
grep -rn "static function booted" app/Models/

# JobAttempted listeners
grep -rn "exceptionOccurred" app/

# Morph pivot table references
grep -rn "morphToMany\|morphedByMany" app/Models/

Arregla todo lo que estas busquedas revelen antes de tocar composer.json.

Paso 3: Verifica PHP 8.3+.

php -v

Sin atajos aqui. Si tu pipeline de CI o servidor de staging ejecuta una version de PHP diferente a la local, verifica esos tambien.

Paso 4: Actualiza las dependencias.

{
    "require": {
        "php": "^8.3",
        "laravel/framework": "^13.0"
    }
}
composer update

Si encuentras conflictos, aislalos:

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

Paso 5: Ejecuta los tests de nuevo.

php artisan test --parallel

Presta especial atencion a los tests de creacion de modelos, tests de queue jobs y cualquier cosa que involucre manipulacion de TTL de cache.

Paso 6: Ejecuta el analisis estatico.

./vendor/bin/phpstan analyse

Las propiedades tipadas de Eloquent significan que PHPStan detecta cosas que no podia antes. Las nuevas advertencias despues de actualizar suelen ser problemas reales, no ruido.

Paso 7 (opcional): Usa Laravel Shift.

Si quieres automatizacion, Shift abre un PR con commits atomicos para cada cambio. Maneja el trabajo mecanico — bumps de dependencias, renombramientos de configuracion, actualizaciones de firmas de metodos — para que tu te enfoques en los cambios incompatibles que necesitan contexto humano.

Consejo profesional: Mantengo un archivo UPGRADE_NOTES.md en cada proyecto. Despues de cada actualizacion de version mayor, escribo que se rompio y como lo arregle. Tres versiones despues, ese archivo me ha ahorrado mas tiempo que cualquier herramienta automatizada.

El cronograma de adopcion que realmente funciona

Esto es algo de lo que nadie habla — no tienes que adoptar cada nueva funcionalidad el primer dia. La actualizacion en si es obligatoria (eventualmente). Las nuevas funcionalidades son opcionales (para siempre).

Este es el ritmo que estoy siguiendo en mis proyectos:

Semana 1: Actualizar, corregir cambios incompatibles, desplegar. Nada elaborado. Solo llega a verde en Laravel 13 con tus patrones de codigo existentes.

Semanas 2-3: Reemplazar cada extension de TTL Cache::get() -> Cache::put() con Cache::touch(). Este es el cambio de menor esfuerzo y mayor impacto que puedes hacer. Busca cualquier patron de obtener-y-luego-guardar con la misma clave y conviertelo.

Mes 2: Empieza a convertir modelos a PHP Attributes, uno por PR. Comienza con los modelos que mas tocas — los que aparecen en mas diffs. No hagas una conversion masiva. Revisa cada uno.

Mes 3: Anade propiedades tipadas a tus cinco o diez modelos mas importantes. Ejecuta PHPStan despues de cada uno. Arregla lo que encuentre. Te sorprenderas.

Continuo: Todos los modelos, jobs y comandos nuevos usan atributos y propiedades tipadas desde el primer dia. El codigo antiguo se convierte naturalmente conforme lo tocas por otras razones.

Si tu equipo no esta listo para una funcionalidad especifica, saltala. Las correcciones de errores de Laravel 12 se mantienen hasta agosto de 2026 y los parches de seguridad hasta febrero de 2027. Esa es tu red de seguridad. Usala.

Que significa esto para la direccion de Laravel

Quiero alejarme un momento porque creo que Laravel 13 senala algo sobre hacia donde se dirige el framework.

Durante anos, Laravel construyo sus propias abstracciones sobre PHP. Propiedades de Eloquent, firmas de Artisan, configuracion por convencion. Eso funciono brillantemente cuando el conjunto de funcionalidades de PHP era limitado. Pero PHP 8.x cambio el juego — atributos, enums, propiedades readonly, constantes tipadas — y el lenguaje en si ahora ofrece soluciones nativas para cosas que Laravel solia resolver con magia del framework.

Laravel 13 es la primera version que abraza seriamente ese cambio. Los atributos no son solo una opcion agradable — son la senal del equipo de que las funcionalidades nativas de PHP son el camino preferido hacia adelante. El nuevo atributo #[Unguarded], que no tiene equivalente basado en propiedades, confirma la direccion: las nuevas capacidades llegaran como atributos primero.

Honestamente, no estoy seguro de todo en esta version. El driver de base de datos de Reverb se siente ligeramente prematuro — me encantaria ver benchmarks con mas de 1,000 conexiones antes de recomendarlo ampliamente. Y las propiedades tipadas de Eloquent, aunque fantasticas para proyectos nuevos, crean un doble estandar en bases de codigo existentes que tomara anos resolver.

Pero la trayectoria es correcta. Un framework que se apoya en su lenguaje en lugar de abstraer sobre el es un framework con un futuro largo. Y un equipo que se enfoca en la estabilidad en produccion sobre funcionalidades de titular es un equipo al que le confio mi infraestructura.

La prueba esta en mis logs de despliegue

En los tres proyectos que he actualizado hasta ahora, asi se ven los numeros:

  • Tiempo de respuesta: 6-8% mas rapido en promedio (mejoras del motor PHP 8.3 mas limpieza del framework)
  • Trafico de red de cache: Reducido 35-42% en el proyecto donde converti las extensiones de TTL a touch()
  • Problemas encontrados por PHPStan: 14 errores de tipo previamente invisibles en los tres proyectos despues de anadir propiedades tipadas
  • Tiempo de actualizacion: 2-3 horas por proyecto para la actualizacion en si; 1-2 horas adicionales para adoptar Cache::touch() y convertir el primer lote de modelos

Las mejoras de rendimiento por si solas justifican la actualizacion. Las mejoras en la experiencia del desarrollador la hacen urgente.

Detalle Valor
Lanzamiento Q1 2026
PHP requerido 8.3 minimo
Correcciones de errores hasta Q3 2027
Parches de seguridad Hasta Q1 2028
Compatibilidad con Symfony 7.4, 8.0
Cambios incompatibles Restricciones de boot en modelos, nomenclatura de pivot morph, API del evento JobAttempted
Nueva instalacion laravel new my-app --dev

Lo que haria el lunes por la manana

Si te alejaras de este articulo e hicieras una cosa manana, esto es lo que elegiria: abre una terminal, ejecuta php -v, y si ves 8.3 o superior, crea una rama y ejecuta composer require laravel/framework:^13.0 --with-all-dependencies. Mira que se rompe. Arreglalo. Ejecuta tus tests.

No lo despliegues. No conviertas tus modelos. No toques tus patrones de cache. Solo haz que la actualizacion funcione en una rama para que sepas exactamente que se interpone entre tu y Laravel 13. Ese conocimiento por si solo cambia tu planificacion de "probablemente deberiamos actualizar algun dia" a "estos son los cuatro archivos que necesitamos cambiar y toma una tarde".

Las mejores actualizaciones son aburridas. Laravel 13 es una actualizacion aburrida de la mejor manera posible — predecible, bien documentada, retrocompatible donde importa, y genuinamente mejor en los lugares que afectan tu trabajo diario.

Tus despliegues del viernes te lo agradeceran. Los mios ya lo hicieron — despues de que arregle ese metodo boot(), claro.


Trabajemos juntos

¿Buscas construir sistemas de IA, automatizar flujos de trabajo o escalar tu infraestructura tecnologica? Me encantaria ayudarte.

Coffee cup

¿Te gustó este artículo?

Tu apoyo me ayuda a crear más contenido técnico detallado, herramientas de código abierto y recursos gratuitos para la comunidad de desarrolladores.

Temas Relacionados

Engr Mejba Ahmed

Sobre el 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

13  +  7  =  ?

Seguir Aprendiendo

Artículos Relacionados

Ver Todos

Comments

Leave a Comment

Comments are moderated before appearing.

Learning Resources

Expand Your Knowledge

Accelerate your growth with structured courses, verified certificates, interactive flashcards, and production-ready AI agent skills.

Sample Certificate of Completion

Sample certificate — complete any course to earn yours

Engr Mejba Ahmed

Engr Mejba Ahmed

Claude Code Expert · Online

👋

Hey there!

Quick Actions

WhatsApp Instant reply

Chat on WhatsApp

+880 1723 741224 · Instant reply

Popular Questions

Engr Mejba Ahmed is connected
Engr Mejba Ahmed is typing...
Engr Mejba Ahmed avatar

✉ Want me to follow up? Drop your email

Engr Mejba Ahmed avatar

📞 Connect Directly

Choose how you'd like to reach me

WhatsApp

+880 1723 741224

Email

[email protected]

✓ Details sent! I'll get back to you shortly.

Powered by OpenAI

335+

Blog Posts

25

AI Courses

63

Projects

Services & Expertise

Pricing & Process

Learning & Resources

Connect & Support