---
title: "Laravel 14: qué se rompe al actualizar y qué cambia solo"
excerpt: "Laravel 14 se cocina en la rama master con PHP 8.4 como mínimo y Symfony 8. Las firmas que cambian, los defaults que cambian sin que toques nada y las novedades ya mergeadas."
date: "2026-09-21T11:00:00.000Z"
category: "Laravel"
tech_article: true
author:
  name: "angel cruz"
  picture: "/images/me/angel-cruz.png"
ogImage:
  url: "/images/open-graph/laravel-opengraph-image.png"
seo_title: "Laravel 14: breaking changes, PHP 8.4 y cómo preparar la actualización"
seo_description: "Qué se rompe al actualizar a Laravel 14: PHP 8.4 mínimo, Queue::pause con nueva firma, chunk y lazy sin mutar el builder, MassPrunable con soft deletes y más."
---

**Laravel 14 es la próxima versión mayor del framework y todavía no está lanzada: se desarrolla en la rama `master` de `laravel/framework`, requiere PHP 8.4 como mínimo y se espera para el primer trimestre de 2027.** Lo que ya está mergeado se puede leer hoy: firmas que cambian de orden y comportamientos por defecto distintos sin que toques una línea.

Todo lo que sigue está comprobado en la rama `master` del repositorio de `laravel/framework`, contrastado contra la rama `13.x`, el 21 de septiembre de 2026. Es una rama de desarrollo, así que pueden entrar más cambios antes del lanzamiento; los que ya están mergeados rara vez se revierten.

## Fecha de lanzamiento y soporte de Laravel 14

Laravel lanza una versión mayor por año, siempre alrededor del primer trimestre. La política de soporte del framework da 18 meses de bug fixes y 2 años de parches de seguridad a cada versión mayor.

| Versión | PHP | Lanzamiento | Bug fixes hasta | Seguridad hasta |
|---------|-----|-------------|-----------------|-----------------|
| 12 | 8.2–8.5 | 24 feb 2025 | 13 ago 2026 | 24 feb 2027 |
| 13 | 8.3–8.5 | Q1 2026 | Q3 2027 | Q1 2028 |
| 14 | 8.4+ | Q1 2027 (previsto) | Q3 2028 | Q1 2029 |

Las tres primeras columnas de las versiones 12 y 13 salen de la tabla de la política de soporte de las notas de lanzamiento oficiales. Las fechas de Laravel 14 son previsiones: la de lanzamiento es la que publica Laravel News, y las dos de soporte se derivan de aplicar los 18 meses y los 2 años a ese trimestre.

De la misma tabla sale un dato práctico: Laravel 12 dejó de recibir bug fixes el 13 de agosto de 2026 y pierde los parches de seguridad el 24 de febrero de 2027, más o menos cuando aparezca Laravel 14. Si tu aplicación sigue en 12, el salto que toca ahora es a 13.

## PHP 8.4 como mínimo

Este es el único breaking change que afecta a todo el mundo por igual. El `composer.json` de la rama `master` declara `"php": "^8.4"`, frente al `"php": "^8.3"` de la rama `13.x`.

```bash
# Comprueba el runtime antes de cualquier otra cosa
php -v
```

Si tu servidor corre PHP 8.3, Laravel 14 no es una opción hasta que actualices el runtime, y te quedas en Laravel 13 (con bug fixes hasta Q3 2027, tiempo de sobra para planificarlo).

El salto arrastra el resto de las dependencias. En `master`, los componentes de Symfony pasan a `^8.1.0` (console, http-foundation, http-kernel, routing, mailer, mime, process, finder, uid, var-dumper y error-handler), y Symfony 8 también pide PHP 8.4. En las dependencias de desarrollo, `orchestra/testbench-core` sube a `^12.0.0` y PHPUnit queda como `^11.5.50 || ^12.5.8 || ^13.0.3`. Si mantienes un paquete con matriz de CI, esos tres son los que te van a romper el pipeline antes que nada.

## Qué se rompe: firmas que cambian

### Queue::pause() cambia el orden de los argumentos

Este es el cambio más fácil de pasar por alto, porque no falla en tiempo de compilación: falla pausando la cola equivocada. En Laravel 13 la firma era `pause($connection, $queue)`, con los dos argumentos obligatorios. En `master` es `pause($queue, $connection = null)`, con la conexión opcional.

```php
// Laravel 13
Queue::pause('redis', 'emails');
Queue::pauseFor('redis', 'emails', 60);
Queue::resume('redis', 'emails');
Queue::isPaused('redis', 'emails');

// Laravel 14
Queue::pause('emails');                 // usa la conexión por defecto
Queue::pause('emails', 'redis');        // o la que le pases
Queue::pauseFor('emails', 60, 'redis'); // el TTL ahora va en el medio
```

Lo mismo aplica a `pauseFor()`, `resume()` e `isPaused()`. Si dejas el orden viejo, `Queue::pause('redis', 'emails')` pausará una cola llamada `redis` en la conexión `emails`, que probablemente no exista. El worker sigue trabajando, la cola que querías detener sigue consumiendo, y nada en los logs te avisa. Busca cada llamada a mano:

```bash
grep -rn "Queue::pause\|Queue::pauseFor\|Queue::resume\|Queue::isPaused" app/ routes/ tests/
```

`pauseAll()`, `resumeAll()` y los paused de nivel global se quedan igual, no reciben argumentos.

### findOr() con un array de IDs

En Laravel 13, `findOr()` con un array invocaba el callback solo si el resultado era `null`, y una colección vacía o incompleta no lo es. En `master` el callback se dispara si no se encontraron todos los IDs que pediste.

```php
// IDs 1 y 2 existen, el 999 no
User::findOr([1, 2, 999], fn () => 'faltan usuarios');

// Laravel 13: devuelve la colección con los dos usuarios encontrados
// Laravel 14: ejecuta el callback y devuelve 'faltan usuarios'
```

La comparación es contra `array_unique($id)`, así que IDs repetidos en la entrada no cuentan de más. Si tu código dependía de recibir el subconjunto encontrado, cámbialo a `find()` y comprueba el conteo tú mismo.

## Defaults que cambian sin que toques nada

Aquí está el código que compila, pasa los tests y se comporta distinto en producción.

### chunk() y lazy() ya no mutan el query builder

En Laravel 13, `chunk()` y `lazy()` aplicaban `offset()` y `limit()` sobre la propia instancia del builder. Al terminar, el builder quedaba sucio con el último `limit` y `offset` del recorrido, así que reutilizarlo devolvía resultados recortados. En `master` ambos métodos clonan el builder antes de iterar.

```php
$query = User::where('active', true);

$query->chunk(100, function ($users) {
    // procesa
});

// Laravel 13: el builder arrastra offset/limit del último chunk
$query->count();

// Laravel 14: el builder sigue intacto, el count es el real
$query->count();
```

El cambio arregla un comportamiento raro, pero lo hace en silencio. Si alguna parte de tu código compensaba la mutación reseteando límites a mano, o dependía de ella, ese apaño ahora sobra o miente.

### MassPrunable borra también los modelos soft deleted

El trait `MassPrunable` de `master` añade `withTrashed()` a la query cuando el modelo usa soft deletes, antes del `forceDelete()`. En Laravel 13 ya hacía `forceDelete()`, pero sin `withTrashed()`, así que los registros con `deleted_at` quedaban fuera del recorrido y sobrevivían al `model:prune`.

En Laravel 14, el mismo modelo y el mismo `prunable()` borran filas que antes se quedaban en la base de datos. Si tu `prunable()` filtra por `created_at` y tienes años de registros soft deleted, el primer `model:prune` tras la actualización va a borrar mucho más de lo habitual.

```bash
# Mira el alcance antes de dejarlo suelto
php artisan model:prune --pretend
```

### Cache::has() y Cache::forget() aceptan arrays

En Laravel 13, `Cache::has(['a', 'b'])` pasaba el array a `get()` y la comprobación no significaba lo que parecía. En `master`, `has()` con un array resuelve por `many()` y devuelve `true` solo si ninguna de las claves falta; `forget()` con un array delega en `deleteMultiple()`.

```php
Cache::has(['user:1', 'user:2']);    // true solo si están las dos
Cache::forget(['user:1', 'user:2']); // borra las dos
```

Si tenías un helper propio que iteraba las claves para simular esto, ya puedes tirarlo. Y si le pasabas un array a `has()` por accidente, el resultado que obtenías antes no significaba lo que parecía.

## Novedades ya mergeadas en Laravel 14

Lo aditivo va en lista corta: es la parte que la documentación oficial cubrirá mejor cuando salga la versión.

**Rutas con el método HTTP QUERY.** `QUERY` entra en el array de verbos del router y aparece `Route::query()`:

```php
Route::query('/search', SearchController::class);
```

**`$user->authorize()`.** El contrato `Illuminate\Contracts\Auth\Access\Authorizable` ahora declara `authorize($ability, $arguments = [])` junto a `can()`, así que la autorización con excepción se puede pedir al propio usuario y no solo al Gate:

```php
$user->authorize('update', $post);
```

**Contexto en `report()`.** Los tres helpers pasan a aceptar un array de contexto que llega al handler de excepciones:

```php
report($e, ['order_id' => $order->id]);
report_if($failed, $e, ['attempt' => $attempt]);
report_unless($ok, $e, ['payload' => $payload]);
```

**`whereKey()` acepta subqueries.** Además de un ID, un array o un modelo, ahora recibe un `Closure`, un query builder o una relación, y los resuelve con `whereIn`. La firma pasa a `whereKey(mixed $id, string $boolean = 'and', bool $not = false)`:

```php
$posts = Post::whereKey(fn ($query) => $query
    ->select('post_id')
    ->from('featured_posts')
)->get();
```

`orWhereKey()` y `orWhereKeyNot()` ya existían en Laravel 13; lo nuevo es el soporte de subqueries y los parámetros de booleano y negación.

**`Storage::fake('ondemand')` para discos on-demand.** `FilesystemManager::build()` pasa a devolver `$this->disks['ondemand']` si ya existe, en lugar de resolver siempre un disco nuevo. Como `Storage::fake()` registra el disco con el nombre que le pasas, eso hace testeable el código que crea discos al vuelo:

```php
Storage::fake('ondemand');

// Dentro del código bajo prueba, esto ahora devuelve el disco falso
Storage::build(['driver' => 's3', 'bucket' => 'facturas']);
```

## Cómo preparar la actualización desde ahora

Todavía no hay nada que actualizar, pero hay trabajo que no depende del lanzamiento:

1. Sube el runtime a PHP 8.4. Laravel 13 soporta 8.3, 8.4 y 8.5, así que puedes mover PHP sin tocar el framework.
2. Haz inventario de las llamadas afectadas: `Queue::pause` y familia, `findOr` con arrays, `Cache::has` con arrays y los `chunk`/`lazy` cuyo builder se reutiliza después.
3. Corre `model:prune --pretend` en los modelos con soft deletes para saber cuánto crece el borrado.
4. Revisa la matriz de CI de tus paquetes: Symfony 8.1, testbench 12 y PHPUnit 11.5/12.5/13.

Cuando salga la versión, el upgrade guide oficial listará cada cambio con su etiqueta de impacto, y [Laravel Shift](https://laravelshift.com/) automatiza buena parte del trabajo mecánico abriendo un pull request con commits atómicos.

Si vienes de más atrás, primero toca el salto a 13, y para eso están [las novedades de Laravel 13](/post/laravel-13-novedades) con su propia lista de breaking changes.

---

## Preguntas frecuentes

### ¿Cuándo sale Laravel 14?

La previsión es el primer trimestre de 2027, siguiendo el ciclo anual del framework. No hay fecha exacta anunciada; Laravel 13 salió en Q1 2026 y Laravel 12 el 24 de febrero de 2025.

### ¿Qué versión de PHP necesita Laravel 14?

PHP 8.4 como mínimo, según el `composer.json` de la rama de desarrollo. Laravel 13 pedía 8.3. El salto va atado a Symfony 8, que también requiere 8.4.

### ¿Cuáles son los breaking changes de Laravel 14?

Los que ya están mergeados: PHP 8.4 mínimo, el nuevo orden de argumentos en `Queue::pause()` y sus hermanos, `findOr()` con arrays invocando el callback cuando faltan IDs, `chunk()` y `lazy()` sin mutar el builder, `MassPrunable` incluyendo los modelos soft deleted, y `Cache::has()`/`Cache::forget()` tratando los arrays como tales.

### ¿Puedo probar Laravel 14 hoy?

Puedes leer y ejecutar la rama de desarrollo, aunque la API puede cambiar hasta el lanzamiento y no sirve para producción. Laravel 13 recibe bug fixes hasta Q3 2027.

### ¿Hasta cuándo tengo soporte si me quedo en Laravel 13?

Bug fixes hasta el tercer trimestre de 2027 y parches de seguridad hasta el primer trimestre de 2028, según la tabla de la política de soporte oficial.

### ¿Laravel 12 sigue soportado?

Solo en seguridad. Los bug fixes terminaron el 13 de agosto de 2026 y los parches de seguridad llegan hasta el 24 de febrero de 2027.

---

## Referencias

- [laravel/framework, rama master en GitHub](https://github.com/laravel/framework/tree/master)
- [composer.json de la rama master](https://github.com/laravel/framework/blob/master/composer.json)
- [Release Notes y política de soporte, documentación oficial](https://laravel.com/docs/13.x/releases)
- [What's coming in Laravel 14, Laravel News](https://laravel-news.com/laravel-14)
- [Laravel Shift](https://laravelshift.com/)

---

## Sitemap

Índice completo del sitio: [/sitemap.md](https://www.angelcruz.dev/sitemap.md)

Canónico HTML: [https://www.angelcruz.dev/post/laravel-14-novedades](https://www.angelcruz.dev/post/laravel-14-novedades)
