
August 12, 2026
11 min read
Table of Contents
By Kokil Thapa | Last reviewed: August 2026
If your application still runs Laravel 10, you are carrying framework debt that compounds every quarter. Laravel 10 reached end-of-life for feature updates, security patches are winding down, and third-party packages increasingly assume Laravel 11 or 12 with PHP 8.2 or higher. This Laravel 12 Real World Migration Guide from Laravel 10 walks through the incremental path I use on production apps — not a theoretical changelog rewrite, but the audit, upgrade, test, and deploy sequence that keeps client sites online. Before you touch composer.json, read what changed in Laravel 12 so you know which breaking changes actually affect your codebase.
Why should you upgrade from Laravel 10 to Laravel 12 in 2026?
Staying on Laravel 10 in 2026 means you inherit risk without gaining speed. Laravel 12 (current major, minimum PHP 8.2) is primarily a maintenance-focused release built on the Laravel 11 application skeleton — cleaner bootstrap, streamlined config publishing, and continued first-class support for Vite 6.x front-end builds. Laravel 11 already removed deprecated APIs that Laravel 10 still tolerated; Laravel 12 finishes that cleanup.
On legal-tech portals and eCommerce systems I maintain, the practical reasons to migrate are operational, not cosmetic:
- Security coverage. Framework and dependency advisories target supported majors. Composer audit warnings on Laravel 10 packages become harder to resolve each month.
- Package compatibility. Spatie, Livewire, Filament, Sanctum, and Horizon releases now assume Laravel 11+ and PHP 8.2.
- Developer velocity. Laravel 11+ skeleton reduces boilerplate; Laravel Pint, PHPStan, and CI pipelines integrate cleanly with the modern structure.
- Hosting alignment. Ubuntu 24.04 servers ship PHP 8.3/8.4; running PHP 8.1 for Laravel 10 forces you to maintain an EOL runtime.
A common mistake is treating this as a single composer update weekend. In practice, plan two upgrade windows — 10→11 and 11→12 — with a full regression pass after each hop. That matches how Laravel 11 restructured the default application and keeps rollback boundaries clear.
| Stage | Laravel 10 (current) | Laravel 11 (first hop) | Laravel 12 (target) |
|---|---|---|---|
| PHP minimum | 8.1 | 8.2 | 8.2 (8.3/8.4 recommended) |
| Support status (2026) | EOL / security only | Supported | Current major |
| App skeleton | Full config files, Kernel.php | Slim bootstrap, middleware in bootstrap/app.php | Same as 11, minor defaults |
| Front-end default | Vite (Mix legacy) | Vite | Vite 6.x |
| Migration effort | — | High (structure + packages) | Low (mostly composer bump) |
| Rollback complexity | — | Moderate | Low if 11 is stable first |
What PHP version do you need before migrating to Laravel 12?
Laravel 12 requires PHP 8.2 or higher. PHP 8.4 is the latest stable in 2026; PHP 8.3 is widely deployed on production VPS hosts. Do not jump straight to 8.4 on day one if your host or CI image lacks it — 8.2 satisfies the framework requirement and keeps risk bounded.
Verify local and server PHP before Composer
php -v
composer check-platform-reqs
php -m | grep -E 'mbstring|openssl|pdo|tokenizer|xml|ctype|json|bcmath' On Ubuntu 22.04/24.04 servers I administer, I install PHP via the ondrej/php PPA and run multiple versions side by side during transition:
sudo add-apt-repository ppa:ondrej/php
sudo apt update
sudo apt install php8.3-fpm php8.3-cli php8.3-mysql php8.3-xml php8.3-mbstring php8.3-curl php8.3-zip php8.3-redis
sudo update-alternatives --set php /usr/bin/php8.3 Fix application code for PHP 8.2+ deprecations
Before changing Laravel, scan your app with static analysis. I've caught dozens of latent issues this way on client upgrades:
composer require --dev phpstan/phpstan larastan/larastan --with-all-dependencies
vendor/bin/phpstan analyse app --level=5 Watch for: dynamic properties on plain classes (PHP 8.2 deprecates them — use typed properties or #[\AllowDynamicProperties] sparingly), nullable implicit parameters, and ${var} string interpolation removed in PHP 8.2+. Run your existing PHPUnit or Pest suite on the new PHP version while still on Laravel 10 — if tests fail here, they will fail louder after the framework bump.
How do you upgrade Laravel 10 to Laravel 11 step by step?
The 10→11 hop carries the real weight. Laravel 11 reshaped the default application structure — fewer default config files, middleware registered in bootstrap/app.php, and removal of app/Http/Kernel.php in fresh installs. Existing Laravel 10 apps keep their Kernel until you migrate manually. Follow the official upgrade guide at laravel.com/docs/12/upgrade alongside these production steps.
Step 1: Create an upgrade branch and pin dependencies
git checkout -b upgrade/laravel-11
composer require laravel/framework:^11.0 --with-all-dependencies
composer require --dev phpunit/phpunit:^11.0 --with-all-dependencies If Composer conflicts, identify blockers immediately:
composer why-not laravel/framework 11.0 Common culprits on apps I upgrade: older spatie/laravel-permission, abandoned UI scaffolding packages, and custom forks pinned to ^10.0. Update each package to its Laravel 11-compatible release before retrying.
Step 2: Adopt the Laravel 11 bootstrap structure
Compare your bootstrap/app.php against a fresh Laravel 11 skeleton. Middleware that lived in app/Http/Kernel.php moves into the bootstrap file:
<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'role' => \Spatie\Permission\Middleware\RoleMiddleware::class,
]);
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create(); You can migrate incrementally — Laravel 11 does not force you to delete Kernel.php on day one if your middleware stack is complex. I've migrated legal-tech portals with fifteen custom middleware classes by aliasing them first, then pruning dead entries.
Step 3: Publish and reconcile config files
Laravel 11 ships slimmer defaults. If your app relies on explicit config values, publish only what you need:
php artisan config:publish caching
php artisan config:publish queue
php artisan config:publish mail Diff published files against your Laravel 10 copies. Pay attention to config/database.php Redis options, config/queue.php retry_after values, and config/filesystems.php S3 disk settings — silent default changes have caused production upload failures on portals using Spatie Media Library.
Step 4: Update Eloquent casts and migrations
Laravel 11 encourages the casts() method on models instead of the $casts property. Both work during transition, but new code should use the method form for Laravel 12 alignment:
protected function casts(): array
{
return [
'published_at' => 'datetime',
'meta' => 'array',
'is_active' => 'boolean',
];
} Laravel 11 also supports per-model migration paths via php artisan make:model -m conventions. Existing migrations remain valid — run php artisan migrate:status on staging before and after upgrade.
Step 5: Rebuild front-end tooling
Laravel 11 expects Vite. If your Laravel 10 app still uses Mix, migrate first — see Vite config for Laravel projects. After the framework bump:
rm -rf node_modules package-lock.json
npm install
npm run build Commit compiled assets if your production server has no Node.js, which is the pattern I use with Deployer releases on shared EC2 infrastructure.
How do you upgrade Laravel 11 to Laravel 12 without breaking production?
Once Laravel 11 runs green in staging, the 11→12 hop is comparatively small. Laravel 12 focuses on maintenance, dependency updates, and new starter kits — most existing Laravel 11 applications require minimal code changes.
Bump the framework constraint
git checkout -b upgrade/laravel-12
composer require laravel/framework:^12.0 --with-all-dependencies
php artisan about Review the Laravel 12 upgrade notes for removals affecting your app. As of 2026, watch for: UUID trait default changes, image validation rule updates, and Carbon 3.x as the default date library. If your app passes dates as strings without type hints, add explicit casting now.
Refresh first-party Laravel packages together
composer require laravel/sanctum:^4.0 laravel/tinker:^2.10
composer require laravel/horizon:^5.30 --with-all-dependencies
composer require livewire/livewire:^3.5 --with-all-dependencies Version numbers shift — always check each package's README for the Laravel 12 compatible tag rather than guessing. Run composer audit after every bump; security advisories blocked on Laravel 10 often clear once you reach 12.
Run automated formatting and static analysis
After both hops, normalize code style before review:
vendor/bin/pint
vendor/bin/phpstan analyse This catches import path changes and deprecated facade usage. See PHP coding standards with Laravel Pint for CI integration patterns.
What should you test after a Laravel 12 migration?
Passing php artisan test is necessary but not sufficient. On a production Laravel application, I run a structured smoke matrix after every major upgrade.
- Authentication flows. Login, logout, password reset, email verification, two-factor if enabled. Sanctum token issuance for mobile or SPA clients.
- Authorization. Role and permission gates — Spatie Permission middleware aliases must still resolve after the Kernel migration.
- File and media handling. Upload, resize, S3/local disk reads. Legal-tech portals with document sharing break here when
storage:linkor disk config drifts. - Payments and webhooks. eSewa, Khalti, Stripe, or PayPal callback URLs must return 200 on test transactions. Replay webhook payloads from logs.
- Queues and scheduler. Dispatch a test job to Redis; confirm Horizon dashboard loads. Run
php artisan schedule:listand trigger one scheduled command manually. - Mail and notifications. Send a test mailable through SES or SMTP; verify queue serialization did not break notification classes.
- API contracts. Hit critical REST endpoints with Postman or your existing collection; confirm pagination and error JSON shape unchanged.
Expand automated coverage before upgrading if manual testing currently carries the load. Even ten feature tests around checkout, booking, or document upload save hours during the 11→12 hop.
How do you deploy Laravel 12 safely on a live server?
The deploy step is where upgrades that passed staging still fail — usually opcache serving old bytecode, wrong PHP-FPM socket, or a queue worker running the previous release. I use Deployer 7 with symlinked releases on several sister sites; the same principles apply to any zero-downtime workflow.
Pre-deploy checklist
- Database backup verified and restorable ( mysqldump or managed snapshot ).
- Maintenance mode plan — use
php artisan down --secret="your-token"for bypass URL if needed. - PHP-FPM pool points to 8.2+ binary matching your CLI version.
- Supervisor or systemd queue workers reference the current release path or restart on deploy.
- Cron entry calls
php artisan schedule:runwith the correct absolute path.
Deploy commands sequence
php artisan down --retry=60
git pull origin main
composer install --no-dev --optimize-autoloader
php artisan migrate --force
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache
php artisan up
sudo systemctl reload php8.3-fpm
sudo supervisorctl restart all After symlink swap with Deployer, reload PHP-FPM every time — opcache does not always pick up new files on busy pools. See zero-downtime deployment for Laravel with Deployer and GitLab CI/CD deploy to a VPS for pipeline templates that run tests before SSH deploy.
Post-deploy monitoring
Watch error rates for thirty minutes minimum. Check storage/logs/laravel.log, Horizon failed jobs, and slow query log if MySQL 8.0/8.4 shows new full table scans. Keep the previous release directory for quick rollback — dep rollback or manual symlink revert — until the business confirms critical flows work.
Budget realistically: a modest Laravel 10 app with good test coverage takes one to three days for 10→11 and half a day for 11→12. Apps with heavy custom packages, Livewire 2, or legacy Mix assets need a week. For teams without dedicated DevOps, hiring a Laravel developer in Nepal for the migration window often costs Rs 80,000–200,000 (~USD 600–1,500) — less than the revenue lost from a botched same-day production upgrade.
What is the fastest path through this Laravel 12 Real World Migration Guide from Laravel 10?
Work in this order: upgrade PHP on staging, fix deprecations while still on Laravel 10, jump to Laravel 11 and stabilize, then bump to Laravel 12. Never combine PHP, framework, and major package upgrades in a single commit. Keep staging mirroring production — same PHP minor, same Redis 7.x, same MySQL version — because database migration best practices only help when the environment matches.
If you are mid-upgrade and stuck, capture composer why-not output, the exact exception from storage/logs, and your php artisan about screen. That triplet resolves most blockers without a rewrite. Follow Laravel best practices as you land on 12 so the next major upgrade is cheaper.
Need hands-on help upgrading a live business app — booking portal, eCommerce store, or legal-tech platform — without downtime? Contact me with your current Laravel and PHP versions, and I will outline a migration plan scoped to your codebase.









