13 April 2026 · Laravel Support · 14 min read

Laravel Version Upgrades: Why Falling Behind Costs More Every Year

Sixty percent of Laravel applications are at least two versions behind. The cost of catching up doesn't grow on a calendar — it grows on a curve.
Laravel Version Upgrades: Why Falling Behind Costs More Every Year
Sixty percent of Laravel applications are at least two versions behind. The cost of catching up doesn't grow on a calendar — it grows on a curve.

That figure — 60% — comes from Jason McCreary, founder of Laravel Shift, based on analytics from over 17,000 applications processed through his upgrade tooling (jasonmccreary.me, Sep 2019). If you own a custom Laravel application that you commissioned more than eighteen months ago, the statistical bet is that it sits in that majority. The reflex when someone tells you "you should upgrade Laravel" is to file it under technical maintenance — not urgent, not customer-facing, a line on the developer's wishlist that gets bumped every sprint.

This article is about why that filing is wrong, what an upgrade actually involves at the mechanical level, and why the cost of catching up grows faster than the calendar suggests.

We've covered the consequences of letting a Laravel application drift in earlier pieces in this series — the security exposure, what happens when the developer who built it leaves, the warning signs that an app has crossed from asset to liability, and what it costs to rescue one once it has. This article is about a more specific question: the upgrade itself. What changes. What the work involves. Why it isn't a linear problem.

Where the support window stands today

As of April 2026, only Laravel 12 and Laravel 13 receive any official support from the framework team. Laravel 13 was released last month — 17 March 2026 — with zero breaking changes. Laravel 12 continues to receive security patches until February 2027. Everything else — Laravel 11, 10, 9, 8, and earlier — is end-of-life (laravel.com/docs/releases, endoflife.date/laravel).

That phrase "end-of-life" sounds dramatic, and the security article in this series covers what it actually means in terms of vulnerabilities and ICO enforcement risk. There's a simpler framing for a non-technical owner: if your application runs anything below Laravel 12, the people who maintain Laravel are no longer fixing problems in your version. New vulnerabilities discovered tomorrow in Laravel 11 will not be patched. Laravel 11's security support ended on 12 March 2026 — about four weeks ago.


Gantt-style timeline of Laravel version support from 2020 to 2028, showing Laravel 8 through 13 as horizontal bars split into bug-fix and security-only periods. A vertical Today marker sits at April 2026. Laravel 8, 9, 10 and 11 are end-of-life. Only Laravel 12 and 13 receive official support.

What actually changes between versions

Each major Laravel release introduces breaking changes that require manual code intervention. The official upgrade guides estimate completion times of 5 to 30 minutes per version, but these assume a fresh application with no customisation, no third-party packages, and no accumulated technical debt. The reality for production SME applications is markedly different.

Take Laravel 8 to 9, released February 2022. The two highest-impact changes were complete replacements of core subsystems. The filesystem layer moved from Flysystem 1.x to 3.x, changing how write operations behave — they now overwrite by default and return false on failure instead of throwing exceptions. The mail system replaced SwiftMailer (unmaintained since December 2021) with Symfony Mailer, breaking every custom transport implementation. Methods overriding Laravel core classes gained PHP return type declarations. The FILESYSTEM_DRIVER environment variable was silently renamed to FILESYSTEM_DISK — a change that breaks existing .env files but doesn't appear prominently in the official guide (laravel.com/docs/9.x/upgrade).

Laravel 9 to 10, released February 2023, removed the $dates model property that had been deprecated for two versions. Every Eloquent model using protected $dates had to migrate to $casts. PHPUnit moved to version 10. Bus::dispatchNow() and dispatch_now() were removed (laravel.com/docs/10.x/upgrade).

Laravel 10 to 11, released March 2024, contained the most dangerous silent breaking change in recent Laravel history. The behaviour of ->change() on database migrations fundamentally changed: when modifying a column, all modifiers — unsigned, default, comment — must now be explicitly re-declared or they are silently dropped. In Laravel 10, missing attributes were preserved. Run a migration designed for Laravel 10 against Laravel 11 and you can lose database constraints without any warning, error, or log entry.

Laravel 11 also introduced what the community calls the "slim skeleton" (laravel.com/docs/11.x/upgrade). New applications now ship without app/Http/Kernel.php, app/Console/Kernel.php, or app/Exceptions/Handler.php. Five default service providers collapsed into one. All middleware, exception handling, and scheduling configuration moved into a single bootstrap/app.php file. The official guide explicitly tells teams not to migrate existing applications to the new structure — but tutorials, blog posts, and AI coding assistants written from March 2024 onwards all default to the new layout. An application stuck on the old structure becomes harder to maintain over time, not because it's broken, but because the documentation around it has moved on.

Laravel 11 to 12, released February 2025, was the smoothest major upgrade in years. Taylor Otwell described it as "primarily a maintenance focused release" (x.com/taylorotwell, Feb 2025). The most disruptive change was the mandatory move to Carbon 3 — the date library Laravel uses internally — where method behaviours differ from Carbon 2 in ways that break existing code. diffInSeconds() now returns floats instead of integers and can return negative values.

Laravel 12 to 13, released last month, has zero breaking changes.

The pattern across these releases is worth noting. The transitions are not equally difficult. Laravel 8 to 9 and Laravel 10 to 11 are the heaviest. Laravel 11 to 12 and 12 to 13 are essentially free. An owner doing one upgrade per year on a current application faces a much smaller individual workload than one doing four upgrades in sequence after years of deferral — and not just because there's more work, but because the work itself is structured differently when compounded.

The annual cadence — and why it changed the calculus

On 25 January 2021, Taylor Otwell announced Laravel was moving from a six-month to an annual major release cycle, writing that the goal was to "ease the maintenance burden" and "relieve the stress of feeling like you are being 'left behind'" (blog.laravel.com/updates-to-laravels-versioning-policy). Laravel 9 was the first annual release, in February 2022. There are no longer any LTS releases. Every major version receives 18 months of bug fixes and 24 months of security fixes from its release date — no exceptions.

This is good news for teams who keep up. Annual releases give the framework team more time to stabilise each version, which is why Laravel 12 and 13 had so few breaking changes. Two years of security cover is more than enough for an organised team running a single upgrade per year.

The bad news is for teams who don't keep up. Under the old six-month cycle, falling two versions behind meant being twelve months stale. Under the annual cycle, falling two versions behind means being twenty-four months stale — and the modern Laravel ecosystem has accelerated around that pace. Package authors, hosting providers, AI coding tools, and tutorials all assume you're on the latest or one version behind. The further you drift, the less of the ecosystem still supports you.

McCreary's 60% figure captures this drift directly. If most Laravel apps are two or more versions behind today, then most Laravel apps are also out of step with the ecosystem that exists around them. That ecosystem mismatch is what makes catch-up upgrades disproportionately expensive.

Why the cost compounds

The simplest way to see why catch-up costs more than incremental upgrades is to look at what Laravel Shift charges. Shift is the industry-standard automated upgrade tool — it handles the mechanical parts of a Laravel version bump and is used on every modern Laravel project worth its salt. The pricing tells the story: a single jump from the latest version costs $19. Each older version jump costs $39. If you need to go from Laravel 6 to Laravel 12, you cannot skip versions — Shift requires you to run them sequentially. Six jumps at $39 each is $234 in tooling costs alone, before any human work, versus $19 for keeping current (laravelshift.com).

That's an 8 to 12× multiplier on the automation layer, which is the cheap part. The expensive part is the human review.

McCreary, who has personally upgraded over 200 applications through his manual "Human Shift" service, gives benchmarks from direct experience: a standard Laravel application can be upgraded across multiple major versions in 3 hours by an expert. A highly customised application with dozens of packages takes "under 20 hours" (jasonmccreary.me, Sep 2019). These are expert times, by the person who built the tooling. For an internal team without his pattern recognition, his testimony from a podcast appearance is more telling: "We would spend weeks upgrading stuff and they weren't always, honestly, sometimes they weren't like billable hours" (Tighten Business of Laravel podcast). Weeks, not hours, even for an experienced agency.

The non-linearity has three sources.

First, deprecation chains. Items deprecated in one version are removed in the next. The $dates model property was deprecated in Laravel 8 and removed in Laravel 10. Bus::dispatchNow() was deprecated in Laravel 9 and removed in Laravel 10. Carbon 2 support was deprecated in Laravel 11 and removed in Laravel 12. A team that upgrades annually addresses each deprecation when it's still a deprecation — a warning, not an error. A team catching up addresses it as a removal — a failure, not a warning. The work is the same conceptually, but the failure mode is harder to debug because there's no friendly deprecation message guiding you to the fix.

Second, the package compatibility cliff. The Laravel ecosystem has a small number of dominant package authors. Spatie alone publishes over 300 packages used in nearly every production Laravel app, and Spatie's policy is published openly: "We only actively maintain the latest version" (spatie.be/docs). Their packages typically support the latest one or two Laravel major versions in new releases. Spatie's laravel-backup v7 now requires Laravel 12 and PHP 8.4. Spatie's laravel-permission v7 requires Laravel 12. An application two versions behind doesn't just need Laravel upgraded — it needs every dependent package upgraded too, in the right order, with each package's own breaking changes resolved along the way. The same pattern applies to Filament, Livewire, and Telescope.

Third, abandoned packages. Packages popular in the Laravel 5 to 8 era — laravelcollective/html, facade/ignition, fideloper/proxy — are no longer maintained. Upgrading isn't a matter of bumping the version. You have to find a replacement, migrate the code that depended on the old one, and resolve any feature gaps. One documented case study tracked an HR SaaS company through a Laravel 7 to 12 upgrade: 11 outdated packages had to be replaced, the project took 6 weeks, and each abandoned dependency was effectively a mini-project inside the larger upgrade.

These three forces interact multiplicatively. A single-version upgrade addresses a handful of deprecations against a current package ecosystem. A four-version upgrade addresses compounded deprecations against a package ecosystem that has moved beyond your starting point on its own track — and where some of your dependencies no longer exist.


The first deferral makes the second deferral more attractive. The second makes the third inevitable.

Line chart comparing two Laravel maintenance strategies from 2023 to 2027. Path A with annual upgrades stays flat at zero marginal cost. Path B with deferral stays at zero for three years then spikes sharply to a forced catch-up project costing fifteen to sixty thousand pounds over six to fourteen weeks.

PHP — the silent second upgrade

Almost every conversation about Laravel upgrades focuses on the framework. The PHP version requirement is often the bigger constraint, and it tends to be discovered late.

Laravel 9 raised the minimum PHP requirement from 7.3 to 8.0.2 — a major-version language jump. PHP 7 to PHP 8 is not a routine upgrade. It's a different language generation, with different type handling, different error behaviour, and different extension compatibility. Code that runs cleanly on PHP 7.4 may throw fatal errors on PHP 8.0 because of changes to how PHP handles things like comparison operators and string-to-number conversion.

Laravel 10 raised the minimum to PHP 8.1. Laravel 11 to PHP 8.2. Laravel 13 to PHP 8.3. The cumulative effect: a Laravel 8 application on PHP 7.4 — a perfectly normal configuration in 2020 — now requires both a Laravel jump of four versions and a PHP jump of five minor versions across a major language boundary. Each PHP version bump has its own list of breaking changes, deprecated functions, and altered behaviours independent of anything Laravel does.

The W3Techs data captures the scale. As of April 2026, 42% of all PHP-using websites are still on PHP 7 or below — versions that cannot run any current Laravel release (w3techs.com/technologies/details/pl-php). The Zend 2025 PHP Landscape Report, surveying 561 respondents, found 38% of teams were running at least one application on an end-of-life PHP version, and the average team operates 2.66 different PHP versions across its application portfolio (zend.com/resources/php-landscape-report).

The compounding pattern is captured in a developer post from someone who went through an upgrade in 2019: "We had to upgrade PHP 5.6 to PHP 7.2 because Laravel didn't support it any more. After upgrading PHP, we noticed that PHPUnit 4 didn't support PHP 7 and so we tried to upgrade it, too. However, Lumen 5.1 only supported PHPUnit 4. So, we ended up to upgrade Laravel and PHPUnit at the same time" (ryutahamasaki.com). That cascade — Laravel needs new PHP, new PHP needs new PHPUnit, but the old Laravel doesn't support the new PHPUnit — is the texture of a real catch-up upgrade. It can't be planned linearly because you don't discover the dependencies until you start hitting them.

Hosting matters too. On Laravel Forge, PHP versions can be installed side-by-side and switched per-site through a dashboard. On a generic VPS provider, the same upgrade requires SSH access, manual package management, extension installation, and Nginx or Apache reconfiguration. For an SME without a systems administrator on staff, the PHP upgrade alone can consume days of billable developer time before any Laravel work begins.

How owners describe the experience

The research for this article surfaced dozens of verbatim quotes from developers and technical decision-makers describing what it's like to live inside an unmaintained Laravel application. The pattern across them is striking. Almost nobody describes a single dramatic failure. They describe a slow accumulation of friction that becomes unworkable years later.

McCreary's own line captures the cycle: "You don't have time to upgrade because you've never taken the time to upgrade" (jasonmccreary.me, Sep 2019). The first deferral makes the second more attractive. The second makes the third inevitable. By the time it becomes urgent, the cost of action has grown well beyond the budget that was available in any of the earlier moments when it would have been cheap.

A developer on Hacker News in late 2025: "We started on Laravel 4 and it languished at that version until someone in leadership agreed to get it updated to version 8" (news.ycombinator.com/item?id=45025685). Another, on a similar thread: "We never did it — started but changes were too hard to manage on the large code base — we have L4 running on PHP 8.1/Mysql 8 and all is good currently!" That second comment is particularly telling. The application "is good currently." It runs. It serves customers. The owner isn't wrong about that. But the maintenance window has narrowed to the point where the only viable strategy is hoping nothing goes wrong, because the cost of change has crossed the threshold where it can be justified incrementally.

A consultant describing the phenomenon in 2022: "Staring in silent terror at just how long ago your server's PHP install stopped receiving security updates" (tighten.com/insights/catching-up-laravel). The framing — terror, silent, staring — is the language of someone who has discovered the problem after it's grown too large to address comfortably. That's the user experience of compound deferral.

One more, from a developer reflecting on a smooth upgrade six months after a Laravel 12 release: "I'd gotten so used to bracing for chaos with every major version that I forgot what a boring, stable upgrade even felt like" (medium.com/@kamrankhalid06). This is the other side of the curve — the team that stays current and finds each upgrade increasingly routine. The annual cadence rewards them. It punishes everyone else.

When to upgrade incrementally, when to do a catch-up project, and when to stop

The temptation when you discover you're four versions behind is to do all the upgrades at once, in one large project. McCreary, who has seen more of these projects than anyone else, recommends specifically against this approach. His position, published on his blog in September 2019: "Too often developers use the upgrade process as an opportunity to rewrite pieces of the application. This is why most upgrades fail" (jasonmccreary.me).

The pattern he describes is one we see consistently in inherited Laravel codebases — and one we covered in detail in the article on auditing a Laravel codebase you've inherited. The team starts the upgrade with good intentions. Three weeks in, they realise the original developer made some structural decisions that no longer make sense. The temptation to "fix it while we're in here" is enormous. Scope expands. Timeline doubles. Budget triples. The project either gets cancelled or grinds toward an exhausted finish.

The discipline that works is to upgrade and only upgrade. Refactoring is a separate project. Rewrites are a third separate project. Mixing them is how 6-week upgrades become 6-month rescues.

That said, there is a point at which an upgrade is no longer the right answer. The signal is not specific to Laravel — it's the same signal that applies across software in general. If the cost of upgrading approaches the cost of rebuilding, and the existing application carries technical debt that will impede every future change regardless, the calculus shifts. We covered the rebuild question in detail in the rescue cost article. The relevant point for upgrade decisions specifically is that the answer is rarely binary. Most applications that look "un-upgradable" are actually "un-upgradable on current resources" — which is a different problem and admits a different solution.


Four-tier Laravel version status guide. Laravel 12 or 13: current, maintain. Laravel 11: end-of-life March 2026, upgrade now. Laravel 10 or 9: end-of-life, assess first. Laravel 8 or below: three or more versions behind with PHP generation boundary, assess urgently.

What it actually costs in the UK

No UK Laravel agency publishes fixed prices for upgrade work, and there's a reason for that. Two applications on the same Laravel version can require wildly different amounts of work depending on package count, customisation, test coverage, and the quality of the original build. Quoting upgrades sight unseen is a way to lose money on every project.

What we can quote is the input cost. IT Jobs Watch reports a median Laravel contractor day rate of £348 to £413 depending on the reporting period (itjobswatch.co.uk/contracts/uk/laravel.do, Feb 2026 / Nov 2025). Agency rates are higher — typical UK Laravel agencies charge between £75 and £160 per hour for project work, with minimum project sizes starting around £20,000 for established Platinum-level partners (clutch.co). From these inputs, the cost ranges look something like this:

A single-version upgrade on a small-to-medium application (5 to 10 days of work) lands somewhere between £1,750 and £4,500 at contractor rates, or £3,000 to £12,000 at agency rates.

A multi-version catch-up on a medium-complexity application (20 to 40 days) sits between £7,000 and £18,000 at contractor rates, or £12,000 to £40,000 at agency rates.

A complex multi-version upgrade with significant package replacements (40 to 60+ days) runs £14,000 to £27,000 at contractor rates or £24,000 to £60,000+ at agency rates.

The wide ranges are not imprecision. They reflect the difference between an application built to current best practices and one carrying years of accumulated decisions. The published market data on UK retainers spans £475 to £10,000 per month across the agencies surveyed for our retainer scope article — a 20× spread that captures the same variability.

Against any of those numbers, the cost of an annual incremental upgrade looks very different. A current Laravel 12 application upgraded to Laravel 13 (zero breaking changes) is hours of work, not weeks. On a maintenance retainer that handles upgrades as part of routine ongoing scope, the marginal cost of staying current is essentially zero — it absorbs into the same monthly budget that pays for security patches, dependency updates, and the rest of the work that keeps an application healthy.

This is the structural argument for staying current. Not that any individual upgrade is dramatically cheaper than the next — it isn't — but that the cost stays predictable, the scope stays manageable, and the application stays inside the supported window where the framework team is still fixing problems on your behalf.

The boring stable upgrade

Sixty percent of Laravel applications are at least two versions behind. That figure was true when McCreary published it in 2019, and it's still true now. The annual release cadence means the percentage doesn't decrease over time — it grows, slowly, as more applications cross the two-version threshold while their owners are looking the other way.

The way out isn't dramatic. It's incremental, scheduled, and boring — the boring stable upgrade the developer in the closing quote forgot existed. The maths only stops compounding when someone deliberately decides to stop letting it compound.

Stop worrying about your Laravel app

Book a free discovery call. We’ll discuss your situation and recommend the right plan.
Book a Call

Prefer email? hello@rockingtech.co.uk