Khurram Shahzad
Laravel 11 vs Laravel 12: Full Upgrade Guide

Laravel 11 vs Laravel 12: Full Upgrade Guide

If you've been putting off upgrading your Laravel application, you're not alone. There's something quietly intimidating about touching a live codebase especially when it powers real users, real revenue, or a client who expects zero downtime. But here's what years of working through Laravel upgrades across 200+ client projects has taught me: the fear is always bigger than the actual work.

This guide walks you through everything from understanding what actually changed between Laravel 11 and Laravel 12, to running your first composer update with confidence, to deploying a fully upgraded app without breaking a single feature. Whether you're jumping from Laravel 10 to 11, or taking the leap straight to Laravel 12, this is the only guide you'll need in 2026.

Not sure if Laravel is even the right framework for your current project? Read this first: Laravel vs WordPress: which is right for you, it might save you a week of work before you even begin upgrading.

Let's get into it.


Laravel 11 vs Laravel 12: What's Actually Different?

Before you run a single command, it helps to understand why this upgrade matters and what you're walking into.

A Quick Version Timeline

Laravel follows a predictable annual release cycle. Understanding the support windows helps you make smarter decisions about when and whether, to upgrade.

VersionPHP RequirementBug Fixes UntilSecurity Fixes Until
Laravel 10^8.1August 2024February 2025
Laravel 11^8.2September 2025March 2026
Laravel 12^8.2March 2026March 2027

If you're still running Laravel 10, its security support window has already closed. That's not a technicality, that's real exposure.

Why the Upgrade Actually Matters

It's tempting to treat a major version bump as optional housekeeping. It isn't. Here's what you're leaving on the table by staying on an older version:

  • Security patches stop coming. Once a version hits end-of-life, known vulnerabilities go unpatched in your codebase.
  • Modern packages move on. Many Laravel packages now require Laravel 11+ or 12+. Staying behind means locking yourself out of the ecosystem.
  • Performance improvements are real. Laravel's routing, caching layer, and database abstractions improve with every major release.
  • Future upgrades get harder the longer you wait. Skipping from Laravel 9 to 12 in one jump is painful. Staying current keeps each upgrade manageable.


Laravel 11 vs Laravel 12 feature comparison table: PHP version, UUID, Carbon, starter kits

Laravel 11 vs Laravel 12 - At a Glance

FeatureLaravel 11Laravel 12
PHP Requirement8.2+8.2+
App StructureStreamlined (1 AppServiceProvider)Same + refined
UUID Defaultv4v7 (ordered)
Carbon Version2.x or 3.x3.x required
Starter KitsStandardOverhauled
Key FocusSimplificationAI-readiness & DX
Breaking ChangesModerateModerate (targeted)


Should You Upgrade Right Now?

Not every upgrade needs to happen today. Here's an honest framework.

Upgrade If…

  • Your application is actively developed and maintained
  • You depend on a package that now requires Laravel 11 or 12
  • You have a working test suite (or can build one quickly)
  • You want continued security support beyond early 2026
  • You're starting a new feature sprint and want a clean foundation

Hold Off If...

  • The project is in a frozen, stable state with no planned development
  • You have zero test coverage and no staging environment
  • Your custom packages or third-party integrations haven't released Laravel 12-compatible versions yet
  • There's no business justification for the risk right now

The Smart Way to Approach It

For small projects, a single afternoon is often enough. For larger codebases, especially enterprise apps with custom database drivers, complex queues, or payment integrations, plan a proper sprint. Create a dedicated upgrade/laravel-12 branch, clone your production database to staging, and treat this like any other high-risk deployment. Because it is one.

Tools like Laravel Shift can automate a significant portion of the changes in the official upgrade guide, which brings the time investment down dramatically, more on that in Section 9.


Pre-upgrade checklist for Laravel upgrade: backup, PHP version, composer audit, test suite

Pre-Upgrade Checklist: Before You Touch a Single File

This section is the most skipped and the most important. Don't start until you've worked through every item here.

Step 1: Back Up Everything

This sounds obvious. People still skip it. Don't.

Database backup:

bash
mysqldump -u root -p your_database_name > backup_$(date +%Y%m%d).sql

Create a dedicated upgrade branch in Git:

bash
git checkout -b upgrade/laravel-12
git push origin upgrade/laravel-12

If you're on a VPS or dedicated server, take a full snapshot before proceeding. Most cloud providers (DigitalOcean, AWS, GCP) allow one-click snapshots from the dashboard.

Step 2: Verify PHP Compatibility

Both Laravel 11 and Laravel 12 require PHP 8.2 as a minimum. PHP 8.3 is also fully supported and recommended for new builds.

Check your current PHP version:

bash
php -v

If you're on PHP 8.1 or lower, upgrade PHP first before touching your Laravel version. Attempting both simultaneously is a recipe for difficult-to-diagnose errors.

Upgrading PHP on Ubuntu/Debian:

bash
sudo apt update
sudo apt install php8.2 php8.2-cli php8.2-fpm php8.2-mysql php8.2-xml php8.2-mbstring

For cPanel environments, PHP version management is handled through MultiPHP Manager in WHM. For cloud hosting (Cloudways, Forge), use the server dashboard to switch PHP versions per application.

Step 3: Audit Your Dependencies

This is where most upgrade headaches actually come from, not Laravel itself, but the packages around it.

Run this command to identify conflicts before changing anything:

bash
composer why-not laravel/framework ^12.0

Common packages that require version updates alongside Laravel:

PackageLaravel 11 VersionLaravel 12 Version
laravel/passport^11.0^12.0
laravel/sanctum^3.3^4.0
laravel/cashier-stripe^14.0^15.0
laravel/spark-stripe^4.0^5.0
nesbot/carbon^2.0 or ^3.0^3.0 (required)

Two packages were removed from Laravel's core dependencies and may cause errors if referenced directly:

  • doctrine/dbal - no longer required for schema operations
  • spatie/once - removed from framework internals

Step 4: Review Your Test Suite

Before upgrading, run your existing test suite and document which tests pass. This becomes your baseline for validation after the upgrade.

bash
php artisan test

If you have no tests, identify at minimum the three most critical user flows (login, checkout, form submission. Whatever applies to your app) and test them manually before and after the upgrade.


Running composer update with all dependencies for Laravel 11 upgrade

Upgrading to Laravel 11: Step-by-Step

This is the section most developers come here for, let's walk through it properly.

Step 1: Update composer.json

Open your composer.json and update the framework requirement:

json
"require": {
    "php": "^8.2",
    "laravel/framework": "^11.0",
    "laravel/sanctum": "^4.0"
}

Also update any other packages listed in your checklist from Section 4.

Step 2: Run Composer Update

bash
composer update --with-all-dependencies

The --with-all-dependencies flag allows Composer to resolve the full dependency tree freely, which prevents a lot of version lock conflicts.

If you encounter unresolvable conflicts, isolate them one package at a time rather than running the full update blindly.

Step 3: Understand the New Application Structure

This is the change that surprises most developers upgrading to Laravel 11 for the first time.

Laravel 11 introduces a significantly simplified application structure. The five default service providers from Laravel 10 are gone:

  • AuthServiceProvider
  • BroadcastServiceProvider
  • EventServiceProvider
  • RouteServiceProvider
  • AppServiceProvider (survives - this is now the only one)

Their responsibilities have moved into bootstrap/app.php, which is now the central configuration point for middleware, exceptions, routing, and service bindings.

Two important notes:

  1. Existing Laravel 10 applications do NOT need to restructure. Laravel 11 fully supports the old directory layout. You only adopt the new structure for fresh installs or if you choose to migrate manually.
  2. api.php and channels.php are no longer scaffolded by default. They still work, they're just not auto-loaded unless you publish them:
bash
php artisan install:api
php artisan install:broadcasting

Step 4: Update Configuration Files

Compare your existing config files against the Laravel 11 defaults. The easiest way is via GitHub:

https://github.com/laravel/laravel/compare/10.x...11.x

Key changes to review:

  • config/app.php - providers array is now minimal
  • config/auth.php - minor updates to guard structure
  • .env.example - new environment variables added

Republish vendor configs where needed:

bash
php artisan vendor:publish --force

Step 5: Update Routing

Route model binding and API route registration now live in AppServiceProvider by default in fresh Laravel 11 installs. If you're migrating from an existing Laravel 10 app, your RouteServiceProvider will continue working without changes.

For teams adopting the new structure, register routes like this in bootstrap/app.php:

php
->withRouting(
    web: __DIR__.'/../routes/web.php',
    api: __DIR__.'/../routes/api.php',
    commands: __DIR__.'/../routes/console.php',
    health: '/up',
)

Step 6: Run Migrations

After updating package versions, publish and run any new migrations:

bash
# Sanctum
php artisan vendor:publish --tag=sanctum-migrations

# Passport
php artisan vendor:publish --tag=passport-migrations

# Cashier Stripe
php artisan vendor:publish --tag=cashier-migrations

# Run all pending migrations
php artisan migrate

Always run migrations on staging first. Review every migration file before executing on production.

Step 7: Test Everything

bash
php artisan test

Beyond your test suite, manually verify:

  • User registration and login flows
  • API authentication (Sanctum / Passport)
  • Payment processing if using Cashier
  • Queue workers and scheduled tasks
  • File uploads and storage operations


Laravel 12 new features: Carbon 3.x, UUID v7, starter kit overhaul, AI integration

What's New in Laravel 12: Features Worth Knowing

Laravel 12 isn't a dramatic departure from 11, it's a refinement, a cleanup, and a strategic push toward AI-native development. Here's what actually changed.

Starter Kits Overhaul

Laravel 12 ships with completely overhauled starter kits. The new kits are cleaner, more opinionated, and better suited to modern frontend architectures. To make sure you have access to the latest kit scaffolding, update your global Laravel installer:

bash
composer global update laravel/installer

If you're encountering issues, a clean reinstall via php.new will get you the latest version.

Carbon 3.x Is Now Required

This is one of the breaking changes that catches teams off guard. Laravel 12 drops support for Carbon 2.x entirely. If your codebase uses Carbon methods that were deprecated or changed between versions, you'll see errors after upgrading.

Update your composer.json:

json
"nesbot/carbon": "^3.0"

Then audit your code for any Carbon 2.x-specific method usage. The most common breaking changes involve:

  • CarbonInterval string casting behavior
  • diffForHumans() option parameters
  • Certain static helper methods that were removed

UUID Version 7 via HasUuids Trait

In Laravel 11 and below, the HasUuids trait generated UUID v4 (random UUIDs). Laravel 12 changes the default to UUID v7, which is time-ordered.

This matters for database performance, ordered UUIDs reduce index fragmentation on large tables, which translates to faster writes and more predictable query plans.

However, if you have existing records with UUID v4 and need to maintain consistency, switch to the new HasVersion4Uuids trait:

php
use Illuminate\Database\Eloquent\Concerns\HasVersion4Uuids;

class User extends Model
{
    use HasVersion4Uuids;
}

Grammar & Database Changes

This is the most technically breaking change in Laravel 12 for teams with custom database drivers.

MySqlGrammar constructor now requires a Connection instance. If you've extended any grammar class, your constructor signature needs updating.

Deprecated and removed APIs:

  • Blueprint::getPrefix() - deprecated, use $connection->getTablePrefix() instead
  • Connection::withTablePrefix() - removed
  • Grammar::getTablePrefix() / Grammar::setTablePrefix() - deprecated
  • Grammar::setConnection() - removed

The new pattern for retrieving table prefix:

php
// Before (deprecated)
$grammar->getTablePrefix();

// After (correct)
$connection->getTablePrefix();

Schema Method Changes

Three schema methods now behave differently in Laravel 12:

  • Schema::getTables() - now returns tables across all schemas by default, not just the current one
  • Schema::getViews() - same multi-schema behavior
  • Schema::getTypes() - same

If your code relies on these returning only the current schema's objects, pass the schema argument explicitly:

php
Schema::getTables(schema: 'your_schema_name');

Additionally, Schema::getTableListing() now returns schema-qualified table names (e.g., public.users instead of users). Update any string comparisons in your code accordingly.

Laravel 12 and AI Integration

One of the most exciting directions in Laravel 12 is its positioning as a first-class framework for AI-powered applications. If you're building AI features into your Laravel app, the ecosystem support has grown significantly.

Want to go deeper on this? The Laravel AI SDK integration guide walks through adding AI capabilities to your Laravel 12 application step by step.


Upgrading from Laravel 11 to Laravel 12 : Step-by-Step

If you've already completed the Laravel 11 upgrade above, this section is your next step. If you're jumping directly from Laravel 10, complete Part 1 first, skipping steps makes debugging significantly harder.

Step 1: Update composer.json

json
"require": {
    "php": "^8.2",
    "laravel/framework": "^12.0",
    "nesbot/carbon": "^3.0"
}

Step 2: Update the Laravel Installer

bash
composer global update laravel/installer

Verify the update:

bash
laravel --version

Step 3: Update Carbon to 3.x

bash
composer require nesbot/carbon:^3.0

After updating, run your test suite specifically targeting any date/time-heavy areas of your application. Carbon 3 is not always drop-in compatible with Carbon 2 code.

Step 4: Handle UUID Changes

Search your models for HasUuids:

bash
grep -r "HasUuids" app/Models/

For each model, decide:

  • New model or data doesn't require v4 consistency? → Keep HasUuids (now UUID v7)
  • Existing data in production using UUID v4? → Switch to HasVersion4Uuids
php
// To maintain UUID v4 behavior
use Illuminate\Database\Eloquent\Concerns\HasVersion4Uuids;

Step 5: Fix Grammar & Database API Changes

Search your codebase for deprecated method calls:

bash
grep -r "getTablePrefix\|setTablePrefix\|withTablePrefix\|setConnection" app/ database/

Update each occurrence to use the new connection-based approach. If you've built custom database drivers or macros, this will require the most attention.

Step 6: Resolve Schema Method Changes

Search for getTables, getViews, getTypes, and getTableListing usage:

bash
grep -r "Schema::getTables\|Schema::getViews\|Schema::getTypes\|getTableListing" app/ database/

Add explicit schema arguments where needed, and update any string-matching logic against getTableListing() results to handle schema-qualified names.

Step 7: Update Starter Kit Configuration

This only applies to projects scaffolded with a Laravel starter kit. Review the new kit defaults and merge any configuration changes that apply to your setup.

Step 8: Run Tests and Confirm the Upgrade

bash
php artisan --version
# Should return: Laravel Framework 12.x.x

php artisan test

Before pushing to production, run through your full manual QA checklist on staging. Especially test:

  • Database queries on large tables (UUID index behavior)
  • Any custom grammar or database driver functionality
  • Date/time operations relying on Carbon
  • Schema introspection if your app uses it


Common Laravel upgrade error: composer dependency conflict and how to fix it

Common Errors During Laravel Upgrade (and How to Fix Them)

Even with proper preparation, errors happen. Here are the most common ones and exactly how to resolve them.

Dependency Conflict Errors

Error:

Your requirements could not be resolved to an installable set of packages.

Fix:

bash
composer why-not laravel/framework ^12.0

This command tells you exactly which package is blocking the resolution. Update that package first, then re-run composer update. If a package hasn't released a Laravel 12-compatible version, check its GitHub issues for a fork or temporary replacement.

PHP Version Mismatch

Symptoms: Random fatal errors after update, Declaration must be compatible with notices

Fix: Verify your CLI PHP and web server PHP are both on 8.2+:

bash
php -v           # CLI version
php-fpm8.2 -v    # FPM version

A common mistake is upgrading CLI PHP but not the FPM version used by Nginx or Apache.

Missing Migration Files After Package Upgrade

Several packages (Cashier, Passport) now require you to manually publish their migrations rather than auto-loading them.

bash
php artisan vendor:publish --tag=cashier-migrations
php artisan vendor:publish --tag=passport-migrations
php artisan migrate --pretend   # Preview changes before running
php artisan migrate

UUID-Related Model Errors

Error: Primary key type mismatches on insert, or duplicate key violations after UUID behavior change

Fix: Add HasVersion4Uuids to models that need to maintain UUID v4 behavior for existing data. Never let UUID behavior change on a model that already has production records without a migration plan.

Grammar/Database Driver Constructor Errors

Error:

Too few arguments to function MySqlGrammar::__construct(), 0 passed

Fix: Update your custom grammar class constructors to accept and pass a Connection instance. Refer to Laravel 12's built-in grammar classes on GitHub as a reference implementation.

Carbon Method Deprecation Warnings / Errors

Common removed methods in Carbon 3:

  • CarbonInterval::cascade() behavior changed
  • Some modifier strings changed syntax

Check the official Carbon 3 migration notes and search your codebase for Carbon usage patterns flagged in their changelog.


Tools to Make Your Laravel Upgrade Easier

You don't have to do all of this by hand. These tools remove a large portion of the manual effort.

Laravel Shift: Automated Upgrade Assistant

Laravel Shift is the most valuable tool in any Laravel developer's upgrade toolkit. It analyzes your codebase and automatically applies the changes documented in Laravel's official upgrade guide from updating composer.json to restructuring service providers to handling deprecated method calls.

Available Shifts include:

  • Laravel 5.x → 12.x (all versions)
  • PHP version upgrades
  • Laravel Mix → Vite migration
  • PHPUnit → Pest migration
  • Tailwind CSS version upgrades

At $99/year for unlimited Shifts across all your projects, it pays for itself on the first upgrade if your time is worth anything.

GitHub Comparison Tool

Before touching any config file, use GitHub's comparison view to see exactly what changed between framework versions:

https://github.com/laravel/laravel/compare/10.x...12.x

This shows every default file change so you can surgically apply only what's relevant to your project.

Tinkerwell

If you're debugging unexpected behavior after an upgrade, Tinkerwell gives you a fast, GUI-based PHP/Laravel REPL. You can test Carbon date behavior, query builder output, and model interactions without spinning up a full request cycle.

Laravel Telescope

Deploy Telescope to your staging environment post-upgrade. It logs every query, exception, queued job and mail, giving you a clear view of what's changed in behavior without needing to reproduce issues manually.


Post Laravel upgrade performance optimization — artisan cache and Core Web Vitals improvement

Post-Upgrade Performance & SEO Best Practices

The upgrade isn't complete when the tests pass. A few more steps ensure your app is performing at its best.

Core Web Vitals After Upgrade

A framework update can occasionally affect your server response times, which feeds into LCP (Largest Contentful Paint). After upgrading, re-run your app through PageSpeed Insights and Google Search Console's Core Web Vitals report.

Optimize Configuration & Caching

bash
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan optimize

Run these commands after deploying to production. They pre-compile configuration, routes, and views for maximum speed.

Security Hardening Post-Upgrade

Laravel 11 introduced automatic password rehashing. When a user logs in, if their password hash was generated with old bcrypt work factor settings, Laravel silently rehashes it to the current standard. This is great for security and requires no developer action, but it's worth knowing it's happening.

Encryption key rotation also new in Laravel 11, lets you rotate your APP_KEY without invalidating existing encrypted data:

env
APP_KEY=base64:newkey==
APP_PREVIOUS_KEYS=base64:oldkey==

Review your middleware stack for any security headers you may have previously added manually. Laravel's defaults have improved, and you may have duplication.

Staging → Production Deployment Checklist

  • All tests pass in staging
  • Migrations previewed with --pretend
  • Config cache cleared and rebuilt
  • Route cache cleared and rebuilt
  • Queue workers restarted: php artisan queue:restart
  • Scheduled task cron verified
  • PageSpeed score checked
  • Error logging monitoring active (Telescope, Sentry, or Bugsnag)
  • Database backup confirmed


Conclusion

Upgrading Laravel feels like a lot until you've done it a few times. Then it becomes routine. A checklist, a branch, a few hours of careful work, and a staging environment that lets you verify before the world sees it.

The Laravel team has made upgrades progressively cleaner with every release. Laravel 11's simplified structure removed complexity that never needed to exist. Laravel 12 sharpens the developer experience further and opens doors to AI-powered features that are genuinely exciting to build with.

Start with a backup. Work in a branch. Use your staging environment like it exists for a reason. And if you're managing multiple client projects or a larger codebase, let Laravel Shift handle the mechanical parts so you can focus on the decisions that actually require your judgment.

You'll get through this upgrade in better shape than you found it and that's exactly the point.


Built something interesting with Laravel 12 or need help managing a complex upgrade across multiple environments? Get in touch, happy to help you get through it cleanly.

FAQs

Both Laravel 11 and Laravel 12 require PHP 8.2 as a minimum. PHP 8.3 is also fully supported and performs well with both versions. If your server is still on PHP 8.1 or lower, you must upgrade PHP before attempting the framework upgrade, running an older PHP version with a newer Laravel release will produce immediate errors.
Update your composer.json to set laravel/framework: ^11.0 and PHP to ^8.2, then run composer update --with-all-dependencies. After that, update dependent packages like Sanctum, Passport and Cashier, publish any new package migrations and run php artisan migrate. Your existing application structure does not need to change, Laravel 11 is backward compatible with the Laravel 10 directory layout.
Largely yes, but with specific breaking changes. The three main areas that need attention are: Carbon 2.x to 3.x (now required), UUID generation changing from v4 to v7 in the HasUuids trait, and Grammar constructor changes requiring a Connection instance. Review the breaking changes section of this guide before upgrading.
Technically possible, but strongly discouraged. Upgrading step by step (10 → 11 → 12) surfaces issues one layer at a time, making them far easier to debug. Combining both jumps at once means if something breaks, you're diagnosing two upgrade's worth of changes simultaneously. The extra hour of doing it in two steps will save hours of debugging.
Laravel Shift is an automated tool that applies the changes from Laravel's official upgrade guide to your codebase, updating composer.json, migrating deprecated APIs, restructuring service providers, and more. It supports upgrades from Laravel 5 through Laravel 12. At $99/year for unlimited runs, it's an easy yes for any developer managing more than one Laravel project.
Most popular packages have already released Laravel 12-compatible versions. The ones that require specific attention are Laravel Passport, Sanctum, Cashier Stripe, and Spark Stripe. All covered in the checklist above. For niche or unmaintained packages, run composer why-not laravel/framework ^12.0 to surface any conflicts before committing to the upgrade.
Laravel 11 reduced the default service provider count from five to one (AppServiceProvider). The responsibilities previously split across AuthServiceProvider, EventServiceProvider, BroadcastServiceProvider, and RouteServiceProvider now live in bootstrap/app.php or directly in AppServiceProvider. For existing Laravel 10 apps upgrading to 11, no migration is required, the old provider structure works without changes.
Laravel 11 receives bug fixes until September 2025 and security fixes until March 2026. Laravel 10 security support ended February 2025, if you're still on Laravel 10, the upgrade is a security obligation, not just a developer preference. Laravel 12 extends your security coverage through March 2027.

Related Posts

Top 20 Website Design Trends for 2026

Top 20 Website Design Trends for 2026

Laravel vs WordPress: When to Choose Which?

Laravel vs WordPress: When to Choose Which?