A Laravel app that was started a few years ago and then "just kept running" is one of the most common things clients send me. It works, but it's on Laravel 7 or 8, PHP 7.4, and a handful of packages that haven't been updated since. Then one day the hosting company drops old PHP versions, or a security issue appears, and the upgrade suddenly becomes urgent.
Here is the checklist I follow. It's not glamorous, but it keeps upgrades boring, and boring is exactly what you want.
1. Take stock before touching anything
- Current Laravel and PHP versions.
- Every package in
composer.jsonandpackage.json, and whether each one is still maintained. - How much test coverage exists. Often the honest answer is "very little".
- Where it's deployed and how.
The package list matters most. Laravel's own upgrade guides are excellent. The surprises usually come from a package that was abandoned two versions ago.
2. Get a safety net
If there are no tests, I write a small set before upgrading anything: log in, create the main records, run the main report, place an order, whatever the business can't live without. They don't need to be perfect. They need to tell me quickly if something important broke.
I also make sure there's a staging environment with a recent copy of the production database (with personal data masked if needed).
3. One major version at a time
Jumping from Laravel 8 straight to 12 in one commit is tempting and almost always painful. I go 8 → 9 → 10 → 11 → 12, running the tests at every step. Each step has its own upgrade guide, and each is much smaller than the total.
Tools like Laravel Shift can automate a lot of the mechanical changes. I use them as a starting point and then review every change, the same way I'd review a pull request from a colleague.
4. Upgrade PHP alongside
Newer Laravel versions require newer PHP. I upgrade PHP on staging at the step that needs it and watch for deprecation warnings. Dynamic properties, stricter type handling and removed functions are the usual suspects.
5. Replace abandoned packages early
When a package is dead, I don't fight it. I look for the maintained alternative or, if the package did something small, I replace it with a few lines of our own code. This is often the biggest part of the job.
6. Front-end build tools
Older apps use Laravel Mix with webpack. Newer Laravel uses Vite. Moving to Vite is usually quick and makes local development noticeably faster, but it's a separate step, and I treat it as one.
7. Deploy like it matters
- Deploy to staging first and click through the main flows by hand.
- Back up the production database right before release.
- Release at a quiet time, with a rollback plan written down.
- Watch logs and error tracking closely for the first day.
What you get at the end
Beyond the version number: security updates again, faster PHP, access to newer Laravel features, and a codebase that new developers can work on without fear. It's also the right moment to add things you've been putting off, such as queues, an API or AI features.
Upgrades are part of my migration and modernization service. If your Laravel app is a few versions behind, send me the composer.json and I'll tell you honestly how big the job looks.