Planning a Laravel Version Upgrade Without Downtime
How to plan a Laravel version upgrade: the support policy that sets your deadline, package and PHP checks, tests, the work on a branch, and a deployment that never takes the site offline.

A Laravel upgrade is two separate jobs. The first is changing the code so the application runs on the new version. The second is getting that code into production while customers keep using the system. Teams usually plan the first and improvise the second, which is how a routine version bump turns into an evening of downtime.
This guide covers both: when an upgrade is due, what to check before touching composer.json, how to do the work on a branch, and how to deploy it so that nobody notices.
Laravel's release policy sets the deadline
Laravel publishes a major version about once a year, early in the year. According to the support policy in the release notes, each major version receives bug fixes for 18 months and security fixes for two years. The same page lists which PHP versions each release supports.
That gives a simple rule. Being one major version behind is fine. Being two behind means you are close to, or past, the end of security fixes. Each upgrade guide describes the step from the previous version only, so every skipped year is another guide to work through later. One upgrade a year, a couple of months after the release when packages have caught up, is the cheapest rhythm.
Read the upgrade guide for every version you cross
The official upgrade guide lists each breaking change with a likelihood of impact: high, medium or low. Read all of it, including the low-impact entries, and mark the ones that touch features you use. If you are crossing two versions, read both guides and plan two upgrades in sequence, with a deployment in between if you can.
Low impact does not mean harmless. A recent guide, for example, changed how the default cache prefix and session cookie name are generated for applications that never set them. Miss that entry and every user can be logged out at deployment. Setting SESSION_COOKIE and CACHE_PREFIX explicitly beforehand avoids it. Entries about sessions, cache, queues and serialization are the ones that matter for a no-downtime release, because they affect data that exists at the moment of the switch.
The time estimate at the top of the guide is for a standard application with current packages. Yours depends on the next section.
Check packages and PHP before the framework
Third-party packages decide how hard the upgrade is. Find out where each one stands before you start:
composer outdated --direct
composer why-not laravel/framework 13.0
Use the version you are moving to in the second command. It lists every installed package whose constraints block that version. For each blocker there are three outcomes: a newer release supports the new Laravel version and you update it, the package is abandoned and you replace it, or it is small enough to bring into your own code. First-party packages such as Sanctum, Horizon or Cashier have their own upgrade notes, and some ship database migrations.
Then check PHP. Each Laravel release supports a range of PHP versions and newer releases drop the oldest ones. If production runs a PHP version the new release does not support, upgrade PHP first, as its own deployment, while still on the old Laravel version. Two small changes are easier to debug than one large one.
Make the tests tell you the truth
An upgrade without tests is checked by clicking around and hoping. If the application has a test suite, get it green on the current version first, so that every failure after the upgrade is caused by the upgrade. If it has none, write feature tests for the flows that would cost money if they broke: signing in, the main form or checkout, one API endpoint per resource, an incoming payment webhook, a queued job and an outgoing email. A dozen HTTP-level tests change the risk of the whole project.
Add static analysis as a second net. PHPStan with the Larastan extension understands Laravel and reports calls to methods that no longer exist or whose signatures changed, including code paths the tests never reach.
Do the Laravel upgrade on a branch, in small commits
- Update within your current major version first. Run
composer update, test and deploy. You then start from the last release of the old version, with its fixes applied. - Change the version constraints listed in the guide's dependency section (the framework, the test tools and first-party packages) and run
composer updateagain. Commit the lock file on its own. - Work through the guide from top to bottom, high-impact items first, one commit per item. Search the code for each class or method the guide mentions.
- Compare your configuration files with those of a fresh installation of the new version. New options and changed defaults show up there. Do not restructure the application to match a new skeleton unless the guide says it is required.
- Run tests and static analysis, then use the application on staging with a copy of production data, with queue workers and the scheduler running.
The guide itself points to Laravel Shift, a commercial, community-run service that applies the mechanical changes and opens a pull request. It saves typing in steps two to four. It does not know your packages or your business rules, so the review and the testing stay with you.
Deploy without taking the site down
Build the release beside the live one
Zero-downtime deployment means the new version is fully built before any visitor reaches it. Each release goes into its own directory, storage and .env are shared between releases, and a symbolic link named current points the web server at the live one.
# inside the new release directory
composer install --no-dev --optimize-autoloader
php artisan migrate --force
php artisan optimize
# switch in one step
ln -s "$RELEASE" /var/www/app/current.new
mv -Tf /var/www/app/current.new /var/www/app/current
# then reload PHP-FPM so OPcache drops the old paths, and:
php artisan queue:restart
Deployment tools and hosted platforms do the same thing under other names. If you pull new code into the live directory instead, the application runs for some seconds with new code and old vendor files, and that gap is where upgrade-day errors come from.
Keep migrations compatible with both versions
For a short time, and again if you roll back, old code runs against the new database schema. So a release may add tables and nullable columns, and it may not rename or drop anything the previous release still reads. Removals go into a later release, once the code that used them is gone. We describe the pattern in detail in database migration with minimal downtime. When several servers deploy at once, php artisan migrate --isolated makes sure only one of them runs the migrations.
Restart everything that holds old code in memory
Queue workers, Horizon and Octane keep the application loaded, so they run the old framework until restarted. Run php artisan queue:restart or php artisan horizon:terminate right after the switch. Jobs that were queued by the old version are processed by the new one, so avoid renaming job classes or changing their constructors in the same release. If the guide lists queue or serialization changes, let the queues drain before you switch. More on worker behavior is in Laravel queues explained.
Rollback, and when a maintenance window is the honest choice
With release directories, rollback is pointing current back at the previous release, reloading PHP-FPM and restarting the workers. It works only because the migrations were additive. Take a database backup before the deployment anyway, and decide in advance who makes the call to roll back.
Some changes cannot be made live, such as a data migration that rewrites a large table. For those, a short announced window is safer than a clever deployment:
php artisan down --render="errors::503" --retry=60 --secret="choose-a-long-token"
# deploy, migrate, verify through the secret address
php artisan up
The --render option pre-renders the maintenance page so it can be served even while Composer is replacing files, and the secret lets your team test the live site before reopening it.
Upgrade in-house or hand it over
A team that deploys weekly, has tests and is one version behind should do this itself. Hand it over when the application is several versions behind, when it depends on abandoned packages, when there are no tests, or when deployment is still a manual copy to the server. In those cases the upgrade is the smaller part of the work, and the rest is building the safety net around it.
That is what a Laravel maintenance and support arrangement covers on an ongoing basis: yearly framework upgrades, security releases and the deployment pipeline. For an application that is far behind, a one-time Laravel migration and upgrade project brings it to a supported version first. To add the skill to your own team, you can hire a Laravel developer who has done these upgrades before.
Frequently asked questions
How often should a Laravel application be upgraded?
Once a year, to the current major version, a few weeks or months after its release. That keeps you inside the bug-fix window and makes each upgrade a single guide. Apply minor and patch releases much more often, since they are not supposed to contain breaking changes.
Can I skip a major version?
You can reach the newest version in one project, but not by skipping the steps in between. Each upgrade guide covers the changes from the previous major version only, so the work is done one version at a time. Deploying each intermediate version is the safer route.
Is Laravel Shift enough on its own?
No. It automates the documented, mechanical changes and gives you a pull request to review. Package compatibility, behavior changes in your own code, testing and the deployment are still yours.
Does a Laravel upgrade require a PHP upgrade?
Sometimes. Each Laravel release lists the PHP versions it supports, and new releases drop older ones. Compare the support table with the PHP version in production. If PHP has to change, do that first and separately.
Add worldwincoder.com as a preferred source on Google, or open this article in your AI assistant to use it as a source.
