Introducción
Laravel 9 se lanzó el 8 de febrero de 2022. En esta guía se resumen los pasos para actualizar de Laravel 8.x a 9.x y los cambios de mayor impacto.El tiempo estimado necesario para la actualización es de unos 30 minutos. Sin embargo, la carga de trabajo puede aumentar según el envío de emails, el almacenamiento de archivos, los casts personalizados y las sobrescrituras de clases core del framework.
Actualización automatizada con Laravel Shift
Puedes automatizar la actualización con Laravel Shift. Shift ayuda a actualizarcomposer.json y los archivos de configuración, y resulta útil como punto de partida para revisar diffs.
Cambios por nivel de impacto
Impacto: alto
- Actualización de dependencias
- Migración a Flysystem 3.x
- Migración a Symfony Mailer
Impacto: medio
- Métodos
firstOrNew/firstOrCreate/updateOrCreatedeBelongsToMany - Casts personalizados y comportamiento con
null - Timeout por defecto del cliente HTTP
- Añadido de PHP Return Types
- Cambio de nombre de configuración
schemade Postgres - Deprecación del método
assertDeleted - Movida del directorio
lang - Cambios en las reglas de contraseña
- Cambios en los métodos
when/unless - Tratamiento de claves de array no validadas en la validación
Pasos de actualización
Actualización de dependencias
Impacto: alto Laravel 9 requiere PHP 8.0.2 o superior. Empieza revisando las dependencias encomposer.json.
- Elimina
facade/ignitiony sustitúyelo porspatie/laravel-ignition:^1.0 - Si usas
pusher/pusher-php-server, actualízalo a^5.0 - Comprueba que los paquetes de terceros que uses tengan versión compatible con Laravel 9
- Si usas el canal de notificaciones de Vonage, revisa también su guía de actualización específica
Requisitos de versión de PHP
Impacto: alto Laravel 9 requiere PHP 8.0.2 o superior. Antes de proceder con la actualización, alinea la versión de PHP en CI, entorno de desarrollo local y producción.Migración a Symfony Mailer
Impacto: alto Uno de los grandes cambios de Laravel 9 es la migración de SwiftMailer (cuyo mantenimiento terminó en diciembre de 2021) a Symfony Mailer. Las aplicaciones que solo usanMail::to()->send() tienen poco impacto, pero si tocas directamente APIs de bajo nivel de SwiftMailer, revísalo.
Dependencias de drivers
De withSwiftMessage a withSymfonyMessage
send, html, raw y plain de Illuminate\Mail\Mailer ahora devuelven Illuminate\Mail\SentMessage en lugar de void. Además, la propiedad message del evento MessageSent pasa a ser Symfony\Component\Mime\Email en lugar de Swift_Message.
Revisión de la configuración SMTP
En Symfony Mailer se ha eliminado la opciónstream de SMTP y las configuraciones soportadas se mueven al nivel superior.
auth_mode explícitamente. Es más seguro migrar a un flujo en el que las direcciones inválidas se validan antes del envío, en lugar de recuperarlas después.
Migración a Flysystem 3.x
Impacto: alto Laravel 9 ha actualizado la implementación interna de la facadeStorage de Flysystem 1.x a 3.x. Los métodos de operaciones de archivo mantienen la compatibilidad en la medida de lo posible, pero hay diferencias en excepciones, valores de retorno y registro de adapters.
Instalación adicional de drivers
Principales cambios de comportamiento de Storage
put,writeywriteStreamsobrescriben por defecto los archivos existentes- Si falla la escritura, devuelven
falseen lugar de lanzar excepción - La lectura de archivos inexistentes devuelve
nullen lugar de lanzar excepción deletesobre un archivo inexistente devuelvetrue- El cached adapter se ha eliminado, así que puedes eliminar la clave
cachede la configuración dedisk
throw.
Storage::extend() para que devuelva directamente un Illuminate\Filesystem\FilesystemAdapter.
firstOrNew / firstOrCreate / updateOrCreate de BelongsToMany
Impacto: medio
En Laravel 8, el array de atributos pasado como primer argumento a estos métodos se comparaba con la tabla intermedia. En Laravel 9 se compara con la tabla del modelo relacionado.
firstOrCreate puede ahora recibir el segundo argumento $values, homogeneizando su comportamiento con el de otras relaciones.
Casts personalizados y null
Impacto: medio
En Laravel 9, si al objetivo del cast se le asigna null, se llama también al método set del cast personalizado. Los casts que no contemplaban null pueden lanzar excepciones tras la actualización.
Timeout por defecto del cliente HTTP
Impacto: medio El timeout por defecto del cliente HTTP pasa a ser de 30 segundos. Antes podía esperar indefinidamente.Añadido de PHP Return Types
Impacto: medio En Laravel 9, para alinearse con los requisitos de PHP y Symfony, se han añadido tipos de retorno a varias clases core. Si heredas clases core de Laravel y sobrescribesoffsetGet, offsetSet, jsonSerialize, open, read, etc., añade los mismos tipos de retorno también a tus implementaciones.
Cambio de nombre de configuración schema de Postgres
Impacto: medio
Si configuras el search path en la conexión Postgres, cambia la clave schema a search_path en config/database.php.
De assertDeleted a assertModelMissing
Impacto: medio
Sustituye assertDeleted, que usabas para verificar el borrado de modelos, por assertModelMissing.
Movida del directorio lang
Impacto: medio
En las nuevas aplicaciones de Laravel 9, la ubicación de los archivos de idioma pasa de resources/lang a lang en la raíz del proyecto. Si solo mantienes funcionando la app existente, el impacto es pequeño, pero si te alineas con el nuevo esqueleto o publicas traducciones desde un paquete, revísalo.
Cambios en las reglas de contraseña
Impacto: medio La reglapassword, que validaba que coincidiera con la contraseña del usuario autenticado, se ha renombrado a current_password.
Cambios en los métodos when / unless
Impacto: medio
En Laravel 8, si pasabas un closure a when o unless, el propio closure se evaluaba como truthy y las bifurcaciones se ejecutaban sin querer. En Laravel 9 el closure se ejecuta y se usa su valor de retorno como condición.
Tratamiento de claves de array no validadas
Impacto: medio En Laravel 9, las claves de array no validadas se excluyen siempre del array que devuelvevalidated(). Si quieres mantener el comportamiento de Laravel 8, llama explícitamente a includeUnvalidatedArrayKeys().
Conclusión
En la actualización de Laravel 8 a 9, lo central es la actualización a PHP 8.0.2, la migración a Symfony Mailer y el soporte de Flysystem 3.x. Revisar primero envío de emails, storage, casts personalizados y helpers de test reduce los fallos posteriores.| Cambio | Impacto | Acción |
|---|---|---|
PHP 8.0.2 / laravel/framework:^9.0 | Alto | Actualizar composer.json y el entorno de ejecución |
| Migración a Symfony Mailer | Alto | Revisar las APIs relacionadas con SwiftMailer y la configuración de mail |
| Flysystem 3.x | Alto | Revisar valores de retorno, excepciones y dependencias de driver de Storage |
Métodos upsert de BelongsToMany | Medio | Revisar que el objetivo de búsqueda pasa a la tabla del modelo relacionado |
Casts personalizados y null | Medio | Corregir para que set() no falle recibiendo null |
| Timeout de 30 s del cliente HTTP | Medio | Indica explícitamente timeout() solo en las peticiones necesarias |
Deprecación de assertDeleted | Medio | Sustituir por assertModelMissing() |
Movida del directorio lang | Medio | Cambiar las referencias de ruta fija por app()->langPath() |
Cambio de regla password | Medio | Actualizar a current_password |
| Exclusión de claves de array no validadas | Medio | Usar includeUnvalidatedArrayKeys() solo cuando sea necesario |
Referencias
- Guía oficial de actualización (inglés)
upgrade.mdde laravel/docs 9.x- Diff del repositorio laravel/laravel (8.x → 9.x)
- Laravel Shift: servicio comunitario que automatiza la actualización
- Documentación de Symfony Mailer
- Documentación de Flysystem 3