Laravel upgrades

Laravel 11 to 12: the official estimate is 5 minutes. Here’s what takes longer

Laravel’s 11 to 12 guide is one of its shortest, and the composer change really is quick. What takes longer are a few behaviour changes that throw no errors: they alter dates, IDs and file paths while your application keeps running. Here’s how we’d look for them.

By itmarkerz Technologies. Updated 30 October 2026.

First decide if 12 is your destination

Laravel 11’s security fixes ended on March 12, 2026. Laravel 12’s end on February 24, 2027, so stopping there gives you a few months before the same conversation comes round again. Our Laravel 11 end-of-life guide makes the case for going straight to 13.

The changes below apply either way, because they arrive at version 12 and carry on into 13. The only reason to stop at 12 is a hard block on PHP 8.2 or a package with no Laravel 13 release. Our package matrix lists the lines that stop at 12.

Step 1: the composer change

The official guide lists three dependencies:

"laravel/framework": "^12.0",
"phpunit/phpunit": "^11.0",
"pestphp/pest": "^3.0"

If Composer refuses, composer why-not laravel/framework ^12.0 shows which package is responsible. Update blocking packages on your Laravel 11 branch and release them first, where you can. That way a package’s own breaking changes don’t get mixed up with the framework’s.

Step 2: Carbon 3

The guide rates this low impact, and for many applications it is. We check it first because it’s the change most likely to produce a wrong number with no error. Laravel 11 allowed Carbon 2 or 3. Laravel 12 allows only 3, so find out where you are:

composer show nesbot/carbon | grep versions

If you’re already on Carbon 3, this step is done. If you’re on 2, the concern is diffInDays(), diffInHours() and the rest of that family. As the Laravel 11 guide warns, they now return floats and can be negative, showing direction. A subscription that was “3 days” overdue might now be -3.25. Search for diffIn and pay most attention to invoices, overdue notices, SLA timers, report buckets and anything stored in an integer column. Then write a test for each one that matters before you upgrade, so you can compare the results afterwards.

Step 3: UUIDs

The HasUuids trait now creates version 7 UUIDs. Existing rows don’t change, and most applications are unaffected. Look harder if any of these apply:

  • A validation rule, database check or regular expression expects a particular UUID version.
  • Another system receives your IDs and is strict about the format.
  • Your code assumes an ordering across old and new records. A table will now hold both kinds, so sorting by ID may not match the order they were created in.

To keep the previous format, use HasVersion4Uuids instead. If you imported the now-removed HasVersion7Uuids trait, switch to HasUuids, or you’ll get a fatal error rather than a subtle one.

Step 4: where your files are

If config/filesystems.php doesn’t define a local disk, its root moves from storage/app to storage/app/private. So older files seem to vanish, because the application is now looking one folder deeper. Open the config file. If local is defined there with a root, as it is in most published configs, nothing changes for you. If you’ve removed it, define it with the old root before you upgrade.

Step 5: the smaller changes, by where they bite

Lower-impact Laravel 12 changes and how to check them
ChangeWho noticesHow to check
The image rule rejects SVGAnyone uploading logos or iconsSearch for image rules. To allow SVG, use image:allow_svg. Only do so if you sanitise or safely serve them
The container respects default property valuesA class with ?Carbon $date = null now gets null, not a resolved instanceLook at constructors with nullable class-typed defaults that you resolve from the container
Schema::getTables() includes all schemasMulti-schema databases and tenancy codePass schema: where you meant one schema. getTableListing() now returns qualified names
mergeIfMissing() treats dots as nestingCode merging keys that literally contain a dotSearch for mergeIfMissing
Duplicate route namesUncached routing now matches the first route registered, as cached routing didLook for duplicate names in php artisan route:list
Concurrency::run keeps array keysCode passing associative arrays and reading results by positionSearch for Concurrency::run
DatabaseTokenRepository takes secondsCustom password-reset token setups onlyLook for code that constructs this class by hand

A few more changes are aimed at package authors and custom database drivers, such as the Blueprint and Grammar constructors. If you maintain those, read the full list. Most applications can skip them.

Step 6: prove it

  1. Run your tests, but expect test tooling changes first, since PHPUnit 11 and Pest 3 have their own upgrade notes.
  2. Upload a file and read it back. Download one that was stored before the upgrade.
  3. Compare date-based output between old and new on the same data: an invoice, an overdue list, a monthly report.
  4. Create a record with a UUID and pass it through whatever consumes it.
  5. Release with the previous version ready to redeploy, and check your logs for a few days.

Do you need help with this?

Often not. A small, well-tested application can follow this page and our upgrade checklist in a short sprint, and an automated tool may cover much of the code change. Bring in someone else when your tests are thin or the date and billing logic is too important to check by eye. Our upgrade service gives you a fixed price after a free assessment. Next, the Laravel 12 to 13 guide covers the following step.

Upgrades we have delivered

Questions

How long does the Laravel 11 to 12 upgrade take?

Laravel’s guide estimates 5 minutes, and that’s fair for changing the version constraint on a clean application. The real time depends on your tests, your packages, and whether any of the behaviour changes below touch code that matters to you.

Does Laravel 12 change my existing UUIDs?

No. Stored IDs stay as they are. New records created with the HasUuids trait get version 7 UUIDs, so a table can hold both formats. That’s fine unless something validates or sorts on the old format.

Should I stop at Laravel 12 or go to 13?

Go to 13 unless you’re stuck on PHP 8.2. Laravel 12 security fixes end on February 24, 2027, while Laravel 13 has them until March 17, 2028.

Do I need to change my PHP version for Laravel 12?

Not to install it. Laravel 11 supports PHP 8.2–8.4 and Laravel 12 supports PHP 8.2–8.5. But php.net ends PHP 8.2 security support on 31 December 2026, so if you’re on 8.2 you’ll want to move soon anyway.

Upgrading from Laravel 11?

Send us your repository or composer.json. We’ll tell you if going straight to 13 is realistic, and give you a fixed price.

We reply within one business day (IST).