Lessons from Modernizing Legacy Laravel Applications
Upgrading a Laravel 5.x application to 11 without downtime taught me more about clean architecture than any greenfield project ever could.
Start with the test suite, not the code
Before touching any application code, I write characterisation tests for every critical behaviour. These are not elegant tests — they just document what the system currently does. When an upgrade breaks one, I know exactly where the regression is rather than discovering it in production.
Upgrade incrementally, not in one jump
Going from Laravel 5.8 to 11 directly is a recipe for an unmergeable diff. I upgrade one major version at a time, running tests and fixing failures at each step. It takes longer on the calendar but produces far fewer surprises and makes each PR reviewable.
Lean on the upgrade guide, then read the release notes
The official Laravel upgrade guide covers breaking changes. The release notes cover new features you can use to simplify code. Both are essential reading. Most modernisations I have done cut more code than they added once I replaced hand-rolled helpers with first-party Laravel features.
Refactor opportunistically
A modernisation PR is not the time for a full refactor. When you find something that clearly needs cleaning — a 300-line controller, a service class doing five things — add it to a backlog and handle it in a separate PR. Mixing concerns in one branch makes review impossible and reduces confidence in the upgrade.
Communicate the value clearly
Non-technical stakeholders do not care that you upgraded to Laravel 11. They care about security patches, performance improvements, and reduced developer friction. Frame the work in those terms and you will get the prioritisation it deserves.