Upgrading from Laravel 12 to Laravel 13: a practical guide
Laravel 12 lost bug-fix support in August 2026. This guide covers the PHP 8.3 requirement, Composer changes, the CSRF middleware rename, cache and session hardening, low-impact changes that often bite, and a safe rollout plan.
8 min read

In this article
Laravel 13 was released on 17 March 2026, and the support clock for Laravel 12 is already running: according to the official support policy, Laravel 12 stopped receiving bug fixes on 13 August 2026 and will receive security fixes only until 24 February 2027. If your application is on Laravel 12, now is a sensible time to plan the upgrade; if it is on Laravel 11 or earlier, it is already outside security support.
The good news is that Laravel 13 was designed as a light upgrade. The official upgrade guide estimates about ten minutes for a typical application, and the release notes say most applications can move without changing much code. The rest of the work is knowing which of the documented changes touch your code, and testing.
This guide walks through the upgrade from Laravel 12 to 13 in a practical order, with the high- and medium-impact changes explained. It is based on the Laravel 13.x release notes and upgrade guide, the laravel/laravel 13.x skeleton and the php.net supported-versions page, all checked on 7 October 2026. At that date the latest framework release was v13.35.0, published on 6 October 2026.
Before you start: check the support timeline
| Version | PHP | Released | Bug fixes until | Security fixes until |
|---|---|---|---|---|
| Laravel 11 | 8.2 - 8.4 | 12 March 2024 | 3 September 2025 | 12 March 2026 |
| Laravel 12 | 8.2 - 8.5 | 24 February 2025 | 13 August 2026 | 24 February 2027 |
| Laravel 13 | 8.3 - 8.5 | 17 March 2026 | Q3 2027 | 17 March 2028 |
Source: Laravel 13.x release notes, support policy table. Each major release gets 18 months of bug fixes and two years of security fixes.
Step 1: Upgrade PHP first
Laravel 13 requires PHP 8.3 or newer. Laravel 12 ran on PHP 8.2, so applications still on 8.2 must move PHP first. Do this as its own change: upgrade PHP, run your test suite on Laravel 12, deploy, and only then upgrade the framework. Splitting the work makes it much easier to tell which change broke what.
Which PHP version to pick? According to php.net, PHP 8.2 receives security fixes only until 31 December 2026, PHP 8.3 until 31 December 2027, PHP 8.4 until 31 December 2028 and PHP 8.5 until 31 December 2029. Laravel 13 supports 8.3 through 8.5. Unless a dependency holds you back, 8.4 or 8.5 gives the longest runway.

Step 2: Update Composer dependencies
The upgrade guide lists these changes to composer.json:
laravel/frameworkto^13.0laravel/tinkerto^3.0phpunit/phpunitto^12.0pestphp/pestto^4.0(if you use Pest)laravel/boostto^2.0(if you use Boost)
Also raise the php constraint to at least ^8.3. Then update and look carefully at what Composer reports:
composer update
composer outdated --directThird-party packages are usually the real bottleneck. If a package has no release supporting illuminate/* version 13, check its repository for an open pull request, consider replacing it, or wait. Do not force-install incompatible versions.
If you create new projects with the Laravel installer, update it too: composer global update laravel/installer, or update Laravel Herd if you use Herd's bundled installer.
Step 3: Handle the high-impact change: request forgery protection
Laravel's CSRF middleware has been renamed from VerifyCsrfToken to PreventRequestForgery, and it now also verifies the request origin using the browser's Sec-Fetch-Site header. The old names, VerifyCsrfToken and ValidateCsrfToken, remain as deprecated aliases, so existing code keeps working, but you should update direct references, especially in tests and route definitions:
use Illuminate\Foundation\Http\Middleware\PreventRequestForgery;
// Laravel 12
// ->withoutMiddleware([VerifyCsrfToken::class]);
// Laravel 13
->withoutMiddleware([PreventRequestForgery::class]);Search the codebase for both old class names. After the upgrade, test any flow where forms are submitted from another origin, such as payment-provider callbacks, embedded widgets or forms posted from a separate marketing site. Those are the places where origin checks are most likely to change behaviour, and webhook routes should be excluded from CSRF protection deliberately rather than by accident.
Step 4: Review the medium-impact changes
Cache unserialisation is locked down
The default cache configuration now includes serializable_classes set to false. This hardens cache unserialisation against PHP deserialisation "gadget chain" attacks if your APP_KEY leaks. If your application deliberately stores PHP objects in the cache, list the allowed classes:
// config/cache.php
'serializable_classes' => [
App\Data\CachedDashboardStats::class,
],The better long-term fix is to cache arrays or other plain data instead of objects.
upsert on MySQL and MariaDB needs uniqueBy
Laravel now throws an InvalidArgumentException if upsert() is called with an empty uniqueBy argument, instead of generating invalid SQL. MySQL and MariaDB ignore the value in practice, but the validation still applies. Search for upsert( and make sure each call passes the unique column list.
Step 5: Scan the low-impact changes that often bite
The upgrade guide lists many low-impact changes. These are the ones most likely to matter in ordinary applications:
| Change | What to check |
|---|---|
| Default cache, Redis prefixes and session cookie name now use hyphens | If you relied on framework fallbacks rather than setting CACHE_PREFIX, REDIS_PREFIX and SESSION_COOKIE, set them explicitly to keep existing keys and avoid logging everyone out |
New skeleton sets session serialization to json | Switching an existing app from php to json invalidates all active sessions; keep php during the upgrade if that is a problem |
MySQL DELETE with JOIN, ORDER BY and LIMIT | These clauses are now compiled instead of silently ignored, so MySQL may throw a QueryException where it previously ran an unbounded delete |
| Domain routes take precedence over non-domain routes | Review apps with subdomain or catch-all routes |
JobAttempted event exposes $exception; QueueBusy renames $connection to $connectionName | Update listeners |
symfony/polyfill-php85 adds global array_first() and array_last() on PHP below 8.5 | Conflicts with legacy helpers of the same name; prefer Illuminate\Support\Arr |
| Default password reset email subject is now "Reset your password" | Update tests and translations that assert the old subject |
Creating a model instance while that model is booting throws LogicException | Move such logic out of boot() methods |
Read the full upgrade guide as well; it also covers contract additions that matter only if you maintain custom cache stores, queue drivers or dispatchers.
Step 6: Compare your config with the new skeleton
The upgrade guide recommends reviewing changes in the laravel/laravel repository. Many are optional, but configuration files often gain new options with secure defaults, such as the cache and session settings above. Use GitHub's compare view between the 12.x and 13.x branches, and adopt changes one at a time with a reason for each.

Step 7: Test and roll out
- Run the full test suite and fix failures before anything else. If coverage is thin, add feature tests for login, checkout, forms and any webhooks before you upgrade.
- Clear and rebuild caches on each environment:
php artisan optimize:clear, thenphp artisan optimize. - Deploy to staging with production-like data and exercise sessions, queues, scheduled tasks and emails.
- Restart long-running processes after deployment (
php artisan reloadhandles queue workers, Reverb and Octane). - Watch error logs closely for the first days after the production release.
Can AI tools do the upgrade?
The upgrade guide points to two automation options. Laravel Shift is a community-maintained service that automates Laravel upgrades. Laravel Boost, Laravel's first-party MCP server, provides a /upgrade-laravel-v13 command for AI coding assistants such as Claude Code, Cursor, OpenCode, Gemini and VS Code; it requires Boost 2.0. Either can save time, but neither replaces reading the diff and running your tests, because only you know which behaviour your users depend on.
What you get in return
Beyond longer support, Laravel 13 adds first-party features described in the release notes, including the Laravel AI SDK for text generation, agents, embeddings and vector stores, JSON:API resources, and semantic and vector search capabilities. None of these is required to upgrade, but they are available once you are on 13.
A simple upgrade plan for a small team
- Day 1: create an upgrade branch, raise PHP to 8.3 or newer locally and in CI, and run the tests on Laravel 12.
- Day 1: update
composer.json, runcomposer update, and list every package that blocks the upgrade. - Day 2: apply the code changes from Steps 3 to 5, run the suite, and fix failures.
- Day 2: deploy to staging and check sessions, queues, scheduled tasks, email and payment callbacks by hand.
- Day 3: release to production at a quiet time with a tested rollback plan, which means a database backup and the previous release kept ready to switch back.
Larger applications with many packages may need longer, mostly for waiting on third-party releases, but the order stays the same.
Summary
Upgrade PHP to 8.3 or newer first, then bump the framework and testing packages, rename CSRF middleware references to PreventRequestForgery, review cache serialisation and upsert calls, and check the low-impact list for prefixes, sessions and MySQL deletes. With a working test suite, most Laravel 12 applications can move to 13 in a day. Doing it before Laravel 12's security support ends in February 2027 keeps you on a supported, patched framework.
Frequently asked questions
How long does the Laravel 13 upgrade take?
The official upgrade guide estimates about ten minutes for a typical application. Real projects take longer mainly because of third-party packages, PHP upgrades and testing.
Do I have to rename VerifyCsrfToken?
Not immediately.
VerifyCsrfTokenandValidateCsrfTokenremain as deprecated aliases, but you should update references toPreventRequestForgery.Will users be logged out after the upgrade?
Only if session cookie names change or you switch session serialisation from
phptojson. SetSESSION_COOKIEexplicitly and keepphpserialisation during the upgrade if that matters.When does Laravel 12 support end?
Bug fixes ended on 13 August 2026 and security fixes end on 24 February 2027, according to the Laravel support policy.
Your next customer could start right here.
Introduce your tool, product or business to readers exploring technology.
Explore placements and request a private quote
Sources
- Upgrade Guide (Laravel 13.x) — Laravel
- Release Notes (Laravel 13.x) — Laravel
- Supported Versions — The PHP Group
- laravel/framework v13.35.0 release — Laravel (GitHub), 2026-10-06
- laravel/laravel 13.x composer.json — Laravel (GitHub)
Written with substantial AI assistance. Facts checked against cited sources. Editorial policy.
Comments
No comments yet. Be the first to join the conversation.
Leave a comment
Every comment is read by a moderator before it appears. Your email address is never published; it is used only to contact you about this comment.
More from Cloudsoft Zone

TutorialLaravel
Laravel AI SDK 1.0 tutorial: build your first AI agent in Laravel 13
Build a tested Laravel 13 AI agent with laravel/ai 1.x: providers, a PHP tool, structured output, queued jobs, fakes for tests, cost caps and a security checklist.
By Cloudsoft Zone

ComparisonLaravel
Laravel Sanctum vs Passport: which API authentication package to use
Sanctum and Passport both authenticate Laravel APIs, but they solve different problems. This comparison explains tokens, SPA cookies, OAuth2 grants, expiry and clean-up in Laravel 13, and when each package is the right choice.
By Cloudsoft Zone

Troubleshooting guideCodeIgniter
CodeIgniter 4 validation not working? 9 causes and fixes
Fix CodeIgniter 4 validation problems fast: wrong input source, lost errors after redirect, permit_empty, strict JSON rules, is_unique placeholders and more.
By Cloudsoft Zone
