What’s Changed and Upgrading

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the section bibliography.

This page is written against Laravel 13.x (13.34.0) on PHP 8.3 to 8.5, checked on 2026-10-05. The newest of the books, Laravel: Up & Running (2nd ed., 2019), describes Laravel 5.8 on PHP 7.1. Since then there have been eight major releases, and the framework’s structure, defaults and recommended packages have changed more than its core ideas. This page summarises the releases, shows what old code does on Laravel 13, and collects in one table the outdated statements that the pages of this section correct one by one. The PHP language side, from PHP 7 to 8.5, is on What’s New and Migration.

Releases from 6 to 13

Laravel has used semantic versioning since 6.0 and ships one major version a year. Each release in one line:

Version Year Main changes

6 (LTS)

2019

Semantic versioning. make:auth moved to laravel/ui. The str_* and array_* helpers and the Input facade removed. Lazy collections, Ignition error page, job middleware.

7

2020

Sanctum (as Airlock), the Http client, custom casts, Blade components as <x-…> tags, fluent Str, built-in CORS, several mailers (MAIL_MAILER).

8

2020

app/Models, class-based factories, Jetstream and then Breeze, job batches, named rate limiters, controller namespace removed from route files, time travel in tests, schema:dump.

9

2022

PHP 8.0. Symfony Mailer, Flysystem 3, Attribute accessors, enum casts, anonymous migrations, lang/ at the root, Vite instead of Mix (9.19).

10

2023

PHP 8.1. Native types in the skeleton, the Process facade, Pennant, Laravel Prompts, Precognition. $dates removed.

11

2024

PHP 8.2. The slim skeleton: bootstrap/app.php instead of the HTTP and console kernels, SQLite and database queues by default, install:api and install:broadcasting, Reverb, casts() method, /up health route, APP_PREVIOUS_KEYS, Concurrency.

12

2025

Minimal breaking changes. React, Vue, Svelte and Livewire starter kits replace Breeze and Jetstream. UUIDv7 for HasUuids.

13

2026

PHP 8.3. The AI SDK, JSON:API resources, PreventRequestForgery with Sec-Fetch-Site, queue attributes and Queue::route(), Cache::touch(), vector search, cache serializable_classes.

Support policy

Each release gets bug fixes for 18 months and security fixes for 2 years:

Version PHP Released Bug fixes until Security fixes until

10

8.1 to 8.3

2023-02-14

2024-08-06

2025-02-04

11

8.2 to 8.4

2024-03-12

2025-09-03

2026-03-12

12

8.2 to 8.5

2025-02-24

2026-08-13

2027-02-24

13

8.3 to 8.5

2026-03-17

Q3 2027

2028-03-17

On 2026-10-05, Laravel 11 and older receive no fixes, 12 receives security fixes only, and 13 is the release to be on. There is no LTS release since 6. Every application upgrades once a year, or at least every second year. Laravel 14 is expected in the first quarter of 2027 and will require PHP 8.4 or later. An application on PHP 8.3 has to upgrade PHP before it can move to Laravel 14. composer prohibits php 8.2 shows what holds an application to a PHP version. In Bookshelf, laravel/laravel itself, laravel/ai, Intervention Image, paratest and the local bookshelf/isbn package require ^8.3.

Old code on Laravel 13

Code from the books and from Laravel 5-era tutorials, run in Bookshelf:

<?php
str_slug('Wild Seed');                                     // 5.7 helper
array_get(['x' => ['y' => 1]], 'x.y');                     // 5.7 helper
Input::get('q');                                           // facade removed in 6
Route::get('/legacy-string-route', 'BookController@index');   // controller strings without a namespace
new class extends Model { protected $dates = ['due_at']; };   // removed in 10
factory(App\Models\Book::class)->make();                   // 5.x factory helper
new App\User;                                              // 5.x model location
Request::create('/?q=')->has('q');                         // has() versus filled()
str_slug('Wild Seed') (5.7 helper)             -> Error: Call to undefined function str_slug()
array_get($a, 'x.y') (5.7 helper)              -> Error: Call to undefined function array_get()
Input::get('q') (facade removed in 6)          -> Error: Class "Input" not found
Route 'BookController@index' (no namespace)    -> 500, log: Target class [BookController] does not exist
$dates = ['due_at'] on a model (removed in 10) -> string
Carbon on a casts() datetime                   -> Illuminate\Support\Carbon
factory(App\Models\Book::class) (5.x helper)   -> Error: Call to undefined function factory()
App\User (5.x model location)                  -> Error: Class "App\User" not found
$request->has('q') on an empty value           -> true / filled: false

Most of this fails loudly, which is the easy case. The $dates line is the dangerous one: the property is silently ignored, so due_at stays a string and code that calls ->isPast() on it fails later and somewhere else. The has() line has not changed, but tutorials often use it where filled() is meant. The fixes are on the pages for each feature: Str::slug() and Arr::get() (Collections and Pagination), [BookController::class, 'index'] (Routing), the casts() method (Eloquent Casts, Accessors and Serialization), class factories (Migrations, Seeders and Factories) and app/Models (Eloquent Models).

The Laravel 11 skeleton

Laravel 11 removed app/Http/Kernel.php, app/Console/Kernel.php, app/Exceptions/Handler.php and most service providers from new applications. Middleware, exception handling and routing moved into bootstrap/app.php (54 lines in Bookshelf), the schedule into routes/console.php, and the remaining providers into bootstrap/providers.php. Bookshelf’s app/Http holds only Controllers, Middleware, Requests, Resources and Responses.

Existing applications do not need to change their structure. The upgrade guide for 11 says so explicitly: an application upgraded from 10 keeps its kernels and providers, and they keep working. The new structure is the default for new applications and what the documentation describes. Moving an old application to it is optional cleanup, and Laravel Shift offers it as a separate step. The mapping is on Directory Structure and Configuration and Middleware.

Upgrading to 13

Laravel 13 has three high-impact items and two medium ones, and most applications upgrade without code changes:

  • Dependencies: laravel/framework ^13.0, laravel/tinker ^3.0, phpunit/phpunit ^12.0, pestphp/pest ^4.0 and laravel/boost ^2.0, plus an updated installer.

  • Request forgery protection: VerifyCsrfToken became PreventRequestForgery. References in bootstrap/app.php, tests (withoutMiddleware(VerifyCsrfToken::class)) and the $except list move to the new class and preventRequestForgery(except: …) (Security: CSRF, Encryption and Hashing).

  • Cache serializable_classes: cached objects come back as __PHP_Incomplete_Class unless listed. In Bookshelf this broke a cached Eloquent model and a cached Collection (Cache and Rate Limiting).

  • upsert on MySQL and MariaDB changed how the unique columns are passed.

The upgrade guide lists the low-impact items, such as cache prefixes, session cookie names and event property renames, each with its likelihood of affecting an application.

Tools for upgrading

  • Laravel Shift (laravelshift.com, commercial) opens a pull request per upgrade step. It covers the version bump, the renamed classes, the configuration files and, optionally, the new skeleton. Running one Shift per major version, in order, is the usual way to bring a 5.x application forward.

  • Rector with driftingly/rector-laravel applies automated refactorings, such as helpers to facades, $dates to casts and string routes to callables, through level sets per version. rector/rector is published as a prebuilt package, and composer require --dev rector/rector driftingly/rector-laravel failed in this environment (Could not authenticate against github.com for the dist archive), so it was not run here.

  • Boost gives a coding agent the /upgrade-laravel-v13 command with the upgrade guide as context (AI SDK, MCP and Boost).

All three work best on a codebase with tests, because an upgrade is mostly verifying that nothing changed. The suite on Testing is what makes a yearly upgrade a day’s work.

Every outdated statement in one table

The books' statements about web development and Laravel that are no longer true, with the version where each changed and the page that covers it. PHP language changes are on the PHP Reference’s migration page.

The books say Changed in Now Page

Models in app/, as App\User (Stauffer)

8

app/Models, App\Models\User

Eloquent Models

Route::get('/', 'BookController@index') with a namespace prefix (Stauffer ch. 3)

8

[BookController::class, 'index']

Routing

$factory->define() closure factories (Stauffer ch. 5)

8

class factories with HasFactory

Migrations, Seeders and Factories

protected $dates, $casts property (Stauffer ch. 5)

10, 11

casts() method

Eloquent Casts, Accessors and Serialization

getTitleAttribute() / setTitleAttribute()

9

Attribute::make(get:, set:)

Eloquent Casts, Accessors and Serialization

$table->increments('id'), manual foreign keys

7, 8

id(), foreignId()->constrained()

Migrations, Seeders and Factories

app/Http/Kernel.php, app/Console/Kernel.php, Exceptions\Handler

11

bootstrap/app.php, routes/console.php

Directory Structure and Configuration

routes/api.php and channels.php in every application

11

install:api, install:broadcasting

Building APIs and API Resources

resources/lang

9, 11

lang/, created by lang:publish

Localization

str_* and array_* helpers, Input facade

6

Str, Arr, str(), $request

Collections and Pagination

php artisan make:auth (Stauffer ch. 9)

6, 8, 12

laravel/ui, then Breeze and Jetstream, now the starter kits on Fortify

Authentication

A plain-text api_token column and the token guard (Stauffer ch. 13)

7

Sanctum with SHA-256 hashed tokens

API Authentication: Sanctum and Passport

Passport for every API

7, 11

Sanctum for first-party clients, Passport opt-in via install:api --passport

API Authentication: Sanctum and Passport

VerifyCsrfToken with $except (Stauffer ch. 3)

13

PreventRequestForgery with Sec-Fetch-Site checks

Security: CSRF, Encryption and Hashing

MD5 or SHA-1 passwords, md5(uniqid()) tokens (Wiley ch. 8; Kromann ch. 14)

always wrong

Hash::make (bcrypt, Argon2id), Str::random

Security: CSRF, Encryption and Hashing

Laravel Mix and mix()

9.19

Vite and @vite

Vite and Frontend Assets

jQuery and XMLHttpRequest for dynamic pages (Nixon, Kromann)

n/a

fetch, Livewire, Inertia

Livewire

Mailable build(), SwiftMailer (Stauffer ch. 15)

9

envelope(), content(), attachments(), Symfony Mailer

Mail and Notifications

QUEUE_CONNECTION=sync, $tries properties, five job traits (Stauffer ch. 16)

11, 13

database queue, Queueable, #[Tries]

Queues and Jobs

EventServiceProvider::$listen (Stauffer ch. 16)

11

event discovery

Events and Listeners

Kernel::schedule() (Stauffer ch. 16)

11

Schedule facade in routes/console.php

Task Scheduling

Pusher, laravel-websockets, a Node Echo server (Stauffer ch. 16)

11

Reverb

Broadcasting and Reverb

Cache::remember() TTL in minutes

5.8

seconds

Cache and Rate Limiting

Caching models and collections

13

arrays, or listed serializable_classes

Cache and Rate Limiting

move_uploaded_file() into the web root, trusting the client MIME type (Nixon ch. 7, Powers ch. 9)

always wrong

store() outside public/, content-based validation

File Storage and Images

new GuzzleHttp\Client() in controllers

7

the Http facade with fakes

HTTP Client

PHPUnit classes with @test, expectsJobs() (Stauffer ch. 12)

10, 11

Pest by default, fakes, attributes

Testing

Homestead and Valet (Stauffer ch. 2)

8, 11

Sail and Herd

Docker and Sail

config/app.php lists every package provider (Stauffer ch. 11)

5.5, 11

package discovery, bootstrap/providers.php

Package Development and Ecosystem

Lumen for APIs and micro-services

10

Laravel itself, with install:api

Building APIs and API Resources

Where older books and tutorials are outdated

  • "Laravel releases an LTS version every two years" stopped after 6. Every release now has 18 months of bug fixes and two years of security fixes.

  • "Upgrade guides are long" was true for 5.x. Laravel 12 and 13 were designed for minimal breaking changes.

  • Upgrading by copying the new skeleton over the old application loses customisations. The upgrade guide, Shift or Rector change only what is needed.