Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Laravel 12 Real World Migration Guide from Laravel 10

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.

Laravel 10 → 12 Migration RoadmapLaravel 10PHP 8.1+PHP 8.2+Server upgradeLaravel 11Structure changesLaravel 12Package refreshProduction deployTests + opcache reloadParallel work during migration• Composer audit + package bumps• PHPUnit / Pest test expansion• Vite 8 asset rebuild• Staging mirror validation
Laravel migration guide — recommended two-hop upgrade path with PHP prep before framework bumps
StageLaravel 10 (current)Laravel 11 (first hop)Laravel 12 (target)
PHP minimum8.18.28.2 (8.3/8.4 recommended)
Support status (2026)EOL / security onlyEOL since March 2026Current major (to Feb 2027)
App skeletonFull config files, Kernel.phpSlim bootstrap, middleware in bootstrap/app.phpSame as 11, minor defaults
Front-end defaultVite (Mix legacy)ViteVite 8.x
Migration effortHigh (structure + packages)Low (mostly composer bump)
Rollback complexityModerateLow 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.

Pre-Migration Audit ChecklistClone production snapshotcomposer auditPackage Laravel 11/12 supportCustom service providersDocument queues, cron, webhooks, paymentsGreen light to upgrade branch
Audit composer packages, integrations, and infrastructure before starting the Laravel migration guide

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.

Migration CI PipelineGit pushComposerinstallPHPUnit+ PHPStannpm buildDeploy to stagingManual smoketests pass?ProductionSmoke test checklist• Login / password reset• File upload + download• Payment callback (eSewa/Khalti)• Queue job + scheduled task
Run PHPUnit, static analysis, and staging smoke tests before each production release during the Laravel migration guide

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.

  1. Authentication flows. Login, logout, password reset, email verification, two-factor if enabled. Sanctum token issuance for mobile or SPA clients.
  2. Authorization. Role and permission gates — Spatie Permission middleware aliases must still resolve after the Kernel migration.
  3. File and media handling. Upload, resize, S3 and local disk reads. Legal-tech portals with document sharing break here when storage:link or disk config drifts.
  4. Payments and webhooks. eSewa, Khalti, Stripe, or PayPal callback URLs must return 200 on test transactions. Replay webhook payloads from logs.
  5. Queues and scheduler. Dispatch a test job to Redis; confirm Horizon dashboard loads. Run php artisan schedule:list and trigger one scheduled command manually.
  6. Mail and notifications. Send a test mailable through SES or SMTP. Verify queue serialization did not break notification classes.
  7. 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.

Post-Upgrade Failure Decision Tree500 error after deploy?Check storage/logs+ APP_DEBUG offAssets 404?Run npm run buildClass not found?composer dump-autoloadStale config?config:clear + cache:clearReload PHP-FPM + opcache
Common Laravel migration guide gotchas — logs, assets, autoload, cache, and opcache stale code

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:run with 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.

Zero-Downtime Release Layout/var/www/app/current → symlink (public web root)releases/12Laravel 10 (old)releases/13Laravel 11 stagingreleases/14Laravel 12 (new)Symlink swap + FPM reloadShared (persistent)• .env• storage/ (uploads, logs)• Redis sessions• MySQL 8.x database
Symlinked Deployer releases let you roll back a Laravel 12 migration without losing uploads or environment config

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-not and composer audit at 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

Laravel 12 requires PHP 8.2 or higher. PHP 8.3 is widely used in production; PHP 8.4 is the latest stable. Upgrade PHP on staging before touching application code.

Small apps: 1–3 days. Medium apps with queues, APIs, and third-party packages: 1–3 weeks. Large legacy codebases: 4–8 weeks. Budget Rs 80,000–400,000 (~USD 600–3,000) for freelance migration work in Nepal.

You can jump directly, but I recommend Laravel 10 to 11 first, then 11 to 12. Each major release has its own breaking changes, and splitting the work makes Composer conflicts, deprecated code, and test failures easier to isolate. On client projects I've migrated incrementally and hit far fewer surprises than attempting a single big-bang upgrade.

Expect middleware registration changes, updated default config files, stricter type hints, removal of deprecated helpers, and package incompatibilities. Laravel 11 slimmed the default skeleton; Laravel 12 continues that direction. Form Request validation, Eloquent casts, and queue job serialization often need attention. Run php artisan route:list and your full test suite after each step. I've seen apps break on custom service providers that relied on removed bootstrap patterns.

Clone production to a staging server running PHP 8.2+, create a git branch, and update composer.json constraints one major at a time. Run composer update, read the official upgrade guide for each version, and diff config files against a fresh Laravel install. Fix deprecations shown in logs, run phpunit or pest tests, then deploy via your normal pipeline. Never upgrade production first. I use Deployer 7 with a staging target before touching the live symlink.

Spatie packages, Sanctum, Passport, Livewire, Maatwebsite Excel, and custom private packages are frequent offenders. Run composer why-not laravel/framework 12.x to see blockers. Check each package's GitHub releases for Laravel 12 support before starting. On production apps I've had to temporarily fork packages or swap alternatives when maintainers lagged behind a new major. Lock working versions in composer.lock and commit it.

Not a full rewrite, but expect changes. Laravel 11 moved middleware to bootstrap/app.php instead of app/Http/Kernel.php in new skeletons. Existing Laravel 10 apps can keep Kernel.php during migration, though aligning with the new bootstrap style reduces future friction. Route files, API resources, and Form Requests mostly carry over. Audit custom middleware for signature changes and ensure route caching still works with php artisan route:cache after upgrade.

Your existing migrations should run unchanged on MySQL 8.0 or PostgreSQL 16. Do not rewrite old migration files unless a column type or index syntax changed. Run php artisan migrate on staging against a production database copy. Watch for Eloquent cast changes in Laravel 11+ that affect how JSON or datetime columns serialize. Back up before upgrading: mysqldump or pg_dump, plus a tested restore. I've avoided schema changes during framework upgrades unless strictly required.

Run your existing PHPUnit or Pest suite on PHP 8.2 before changing Laravel versions. After each major bump, re-run tests and manually hit auth, file uploads, queued jobs, scheduled tasks, and payment webhooks. Feature tests catch routing and middleware breaks; unit tests catch type and cast issues. Add smoke tests for critical paths if coverage is thin. On real client projects, I test eSewa and Khalti callback URLs on staging because gateway IP whitelists often block local environments.

Run composer dump-autoload -o, clear caches with php artisan optimize:clear, and confirm APP_ENV matches your .env. Namespace changes in moved classes are common after package updates. Check config/app.php aliases and any manual classmap entries. If opcache serves stale classes on production, reload PHP-FPM after deploy. I've fixed many post-upgrade 500 errors simply by deleting bootstrap/cache/*.php and redeploying with a fresh composer install --no-dev on the server.

Rebuild only if the codebase is unmaintainable, has no tests, and business logic is minimal. For working production apps with real users and data, incremental migration is almost always cheaper and safer. A rewrite sounds clean but usually takes 3–5 times longer and introduces new bugs. I've modernised legacy Laravel 6 apps incrementally through Laravel 12 without a full rewrite. Migrate when security support ends or packages you depend on drop Laravel 10 compatibility.

Confirm the server runs PHP 8.2+ with required extensions: mbstring, openssl, pdo, tokenizer, xml, ctype, json, bcmath, fileinfo. After symlink swap, run php artisan config:cache, route:cache, and view:cache in production. Reload PHP-FPM to flush opcache. Ensure cron still points to the current release path if you use Deployer 7; stale paths break scheduled tasks. Queue workers need supervisor restarts. Several sites I maintain on shared EC2 use this exact post-deploy sequence without downtime.

Laravel 12 inherits security patches and hardened defaults from versions 11 and 12, including improved validation, updated dependencies with CVE fixes, and better cookie and session handling. Running unsupported Laravel 10 versions means missing security releases. Upgrade PHP alongside the framework because PHP 8.1 and older versions no longer receive security updates. Enable APP_DEBUG=false in production, rotate APP_KEY only with a planned session invalidation strategy, and review CORS and Sanctum token settings after upgrade.

Classic causes: production still runs PHP 8.1, missing PHP extensions, wrong file permissions on storage/ and bootstrap/cache/, stale opcache, or .env differences. Case-sensitive Linux paths expose macOS typos. Run php -v and php -m on both environments and compare. Check Apache or Nginx error logs and storage/logs/laravel.log. I've fixed deploy failures caused by www-data lacking write access after a release swap, and by CI installing dev dependencies while production expected --no-dev.

Read the Laravel 11 upgrade guide first, then the Laravel 12 upgrade guide on laravel.com/docs. Each page lists breaking changes, removed features, and config diffs. Use laravel-shift.com for automated PRs if budget allows; Shift costs roughly USD 9–29 per jump. Cross-check with your installed packages' changelogs. Keep a rollback branch and database backup until production runs cleanly for at least one full business cycle including month-end or payment reconciliation jobs.

Share this article

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.

Quick Contact Options
Choose how you want to connect me: