
August 12, 2026
14 min read
By Kokil Thapa | Last reviewed: September 2026
Your app still runs Laravel 10. That means framework debt grows every quarter. Security patches are thinning out. Packages assume Laravel 11 or 12 with PHP 8.2 or higher. This laravel migration guide covers the two-hop path I use on production apps — audit, upgrade, test, deploy — not a changelog summary. Before you edit composer.json, read what changed in Laravel 12 so you know which breaking changes hit your codebase.
Why should you follow a laravel migration guide from Laravel 10 to 12 in 2026?
Staying on Laravel 10 in 2026 means you carry risk without gaining speed. Laravel 12 needs PHP 8.2 or higher. It builds on the Laravel 11 skeleton — slimmer bootstrap, cleaner config, and first-class Vite 8.x front-end builds. Laravel 11 reached end-of-life in March 2026. Laravel 12 is supported through February 2027.
On legal-tech portals and eCommerce systems I maintain, the reasons to migrate are operational:
- Security coverage. Advisories target supported majors. Composer audit warnings on Laravel 10 packages get harder to clear each month.
- Package compatibility. Spatie, Livewire, Filament, Sanctum, and Horizon releases now assume Laravel 11+ and PHP 8.2.
- Developer velocity. The modern skeleton cuts boilerplate. Laravel Pint, PHPStan, and CI pipelines fit the new structure cleanly.
- Hosting alignment. Ubuntu 24.04 servers ship PHP 8.3 and 8.4. Running PHP 8.1 for Laravel 10 forces an EOL runtime.
A common mistake is treating this as one composer update weekend. 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 | EOL since March 2026 | Current major (to Feb 2027) |
| 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 8.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 starting this laravel migration guide?
Laravel 12 requires PHP 8.2 or higher. PHP 8.4 and 8.5 are current in 2026. PHP 8.3 is widely deployed on production VPS hosts. Do not jump to 8.5 on day one if your host or CI image lacks it. PHP 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 and 24.04 servers I administer, I install PHP via the ondrej/php PPA. Multiple versions run 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. Also check nullable implicit parameters and removed ${var} string interpolation. Run your 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.
Run composer audit with Composer 2.10 before any bump. Export your php artisan about output and queue worker config. Use the JSON formatter to validate API response fixtures you will replay during smoke tests.
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. Fresh installs drop app/Http/Kernel.php. Existing Laravel 10 apps keep their Kernel until you migrate manually. Follow the official 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. New code should use the method form for Laravel 12 alignment:
protected function casts(): array
{
return [
'published_at' => 'datetime',
'meta' => 'array',
'is_active' => 'boolean',
];
} Existing migrations remain valid. Run php artisan migrate:status on staging before and after upgrade. Follow database migration best practices in Laravel and review zero-downtime Laravel database migrations if you deploy schema changes alongside the framework bump.
Step 5: Rebuild front-end tooling
Laravel 11 expects Vite. If your Laravel 10 app still uses Mix, migrate first. 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. That is the pattern I use with Deployer releases on shared EC2 infrastructure — the same approach behind Adventure Third Pole Trek.
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 need 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 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. Consider migrating tests to Pest — see Laravel testing with Pest if your suite still runs on PHPUnit 10.
What should you test after completing this laravel migration guide?
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 and 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 after following this laravel migration guide?
The deploy step is where upgrades that passed staging still fail. Usually opcache serves old bytecode, the wrong PHP-FPM socket is active, or a queue worker runs 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. Also review the Laravel production deployment checklist and how to roll back a failed deployment safely.
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.4 or 9.7 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). That beats the revenue lost from a botched same-day production upgrade. Professional website migration services in Nepal and ongoing support and maintenance cover the full cycle if your team lacks bandwidth.
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 8.x, same MySQL version. Follow Laravel best practices as you land on 12 so the next major upgrade is cheaper. 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. For hands-on scoping, contact me with your current Laravel and PHP versions.
Key Takeaways
- Follow a two-hop laravel migration guide: Laravel 10→11 first, then 11→12 — never combine both in one deploy.
- Upgrade PHP to 8.2+ and fix deprecations while still on Laravel 10, before touching the framework constraint.
- Run
composer why-notandcomposer auditat each hop; package conflicts cause most upgrade stalls. - Rebuild Vite 8 assets, run PHPUnit or Pest, and smoke-test payments, uploads, and queues on staging before production.
- Reload PHP-FPM after every deploy — opcache stale bytecode is the top post-migration production failure I see.
- Keep the previous symlinked release for rollback until critical business flows pass manual verification.
People Also Ask
Can you skip Laravel 11 and go straight from Laravel 10 to Laravel 12?
No — not safely on a real codebase. Laravel 11 introduced the bootstrap structure, middleware registration changes, and package compatibility shifts your app depends on. Jumping two majors in one Composer bump makes debugging nearly impossible. Upgrade to Laravel 11, stabilize in staging, then bump to Laravel 12 in a separate branch and deploy window.
How long does a Laravel 10 to 12 migration take?
A modest app with good test coverage typically needs one to three days for the 10→11 hop and half a day for 11→12. Apps with legacy Mix assets, Livewire 2, or fifteen-plus custom packages can need a full week. Add another day if PHP must be upgraded on the production server first.
What is the most common cause of failure after a Laravel upgrade?
Stale opcache and unrestarted queue workers top the list. The app passes tests but production serves old bytecode or background jobs run code from the previous release. Always reload PHP-FPM, restart Supervisor workers, and verify cron paths after deploy. Missing npm run build output causing 404 asset errors is a close second.
Do you need to change database migrations when upgrading to Laravel 12?
Existing migration files remain valid. You do not rewrite history. Run php artisan migrate:status before and after each hop. If you add new columns during the upgrade window, use backward-compatible migrations — add nullable columns first, backfill data, then enforce constraints in a later deploy per zero-downtime migration patterns.
Plan your Laravel 12 upgrade with confidence
This laravel migration guide gives you the sequence, commands, and deploy checks I use on production apps — booking portals, eCommerce stores, and legal-tech platforms. The work is predictable when you split it into two hops and test integrations that actually earn revenue. If you want a scoped migration plan for your codebase without downtime risk, get in touch through the contact page with your current Laravel and PHP versions, package list, and hosting setup.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

