One evening. That was the Laravel 9 upgrade on a mid-size project last week. Most of the diff was composer.json and a few config files.
Laravel 9 is out this month. Symfony 6 components under the hood, PHP 8.0 minimum, Flysystem 3. And from now on, one major per year. The upgrade guide is short, and the “high impact” section is shorter. This is a policy: small majors, often.
I want to defend this policy, because I remember the other kind. A project that sat on an old major for three years, because “we will upgrade when there is time”. There is never time. Then the version goes EOL, a security fix forces the jump, and you pay three years of drift in one horrible month. Packages you depend on drop support one by one, and suddenly it is not a framework upgrade anymore. It is archaeology.
Yearly majors turn this into a subscription. You pay a little every year. An evening, maybe a weekend. The price is predictable, so it goes into the plan like any other maintenance.
What actually took time in my upgrade was two community packages that pinned illuminate components too tightly. This is the usual shape: framework breaking changes are documented, package breaking changes are a surprise. So the first step of any upgrade is reading your own composer.json and asking each line: who maintains you, and are you ready.
My budget rule now: one day per year per project for the framework major, reserved in advance. If the upgrade fits in a day, good. If it does not, that is a signal about the project.
The three-year project was mine. I was the one who said “when there is time”.