Every few weeks someone sends me a variation of the same email: "We're on Laravel 8. What would a Laravel upgrade cost to get us current?" It is a completely reasonable question, and it is also unanswerable in the form it is asked. The honest answer is that the same sentence — "upgrade our Laravel app" — can mean 60 hours or 900 hours depending on eight variables that have nothing to do with which version number you are moving from.
This post is written for the person signing the invoice, not the person writing the code. I have spent 14 years in PHP and Laravel, most of it either building systems or being called in after someone else's upgrade stalled. Below is the cost model I actually use when scoping this work: the drivers, ballpark hour and dollar ranges with stated assumptions, realistic calendar timelines, a set of audit commands your team can run this afternoon, and a weighted scorecard for the question everybody eventually asks — should we just rewrite it instead?
Why "How Much Does a Laravel Upgrade Cost" Has No Single Answer
A Laravel version upgrade is not a product feature with a fixed shape. It is a risk-reduction project whose size is set by how much drift has accumulated since the last time anyone touched the framework layer. Two apps on the same Laravel version, with the same line count, can differ by 5x in effort.
It also helps to know where the clock actually stands. As of September 2026, this is the official Laravel support picture:
| Laravel | Supported PHP | Released | Bug Fixes Until | Security Fixes Until |
|---|---|---|---|---|
| 10 | 8.1 – 8.3 | Feb 14, 2023 | Aug 6, 2024 | Feb 4, 2025 (EOL) |
| 11 | 8.2 – 8.4 | Mar 12, 2024 | Sep 3, 2025 | Mar 12, 2026 (EOL) |
| 12 | 8.2 – 8.5 | Feb 24, 2025 | Aug 13, 2026 | Feb 24, 2027 |
| 13 | 8.3 – 8.5 | Mar 17, 2026 | Q3 2027 | Mar 17, 2028 |
Laravel provides bug fixes for 18 months and security fixes for 2 years per major release, with a new major roughly every Q1. Laravel 13 is the current stable release and requires PHP 8.3 minimum.
On the PHP side: PHP 8.2 leaves security support on December 31, 2026, and PHP 8.3's active support already ended December 31, 2025 (security-only through the end of 2027). PHP 8.4 and 8.5 are the versions worth targeting today.
Two practical consequences for budgeting:
- If you are on Laravel 11 or below, you are already running unpatched framework code. That converts the upgrade from a "nice to have" into a security and compliance line item.
- If you are on Laravel 12, you have runway until early 2027 — which means you can plan an upgrade rather than emergency-fund one. Planned upgrades cost roughly half of panicked ones.
The Eight Cost Drivers That Actually Move the Number
When I scope this work, I am pricing these eight things. Nothing else meaningfully changes the estimate.
1) Laravel Version Distance
Distance is non-linear, not additive. Laravel 10 → 13 is genuinely small; the framework's recent releases have deliberately minimized breaking changes, and Laravel 13 in particular is a modest upgrade for most apps. Laravel 5.x → 13 is a different species of project, because you cross the 5.5/6 helper reorganization, the Symfony Mailer swap in 9, the invokable validation rules in 10, and the whole restructured application skeleton in 11.
You also cannot skip versions safely. As I covered in my guide to migrating legacy Laravel apps, Laravel's upgrade guides assume you are arriving from the immediately previous release, so each hop you skip becomes undocumented territory you have to reverse-engineer.
2) PHP Version Jump
The PHP jump often costs more than the Laravel jump, and teams consistently under-budget it. PHP 8.0's stricter type coercion, 8.1's readonly and enum semantics, 8.2's deprecation of dynamic properties, and 8.4's implicit-nullable deprecation all break real application code — usually in the oldest, least-tested corners.
If you are coming from PHP 7.x, budget the PHP work as its own phase with its own line item.
3) Test Coverage
This is the single biggest multiplier in the model. Automated tests are what let you upgrade by running a suite instead of by clicking through the app for three days after every change.
- 60%+ meaningful coverage on business-critical paths: baseline effort
- 20–40% coverage: roughly 1.4x
- Effectively zero coverage: 1.8x–2.5x, because you must first write characterization tests before you can safely change anything
Writing the safety net is not overhead. It is the cheapest insurance available on this kind of project.
4) Third-Party Package Health
Every abandoned package is a small project hiding inside your upgrade. You get one of four outcomes per package: it already supports your target, a maintained fork exists, a replacement exists but the API differs, or you own it now.
The last outcome is the expensive one. A dead payment gateway wrapper or a bespoke PDF/reporting package can eat 20–80 hours by itself.
5) Custom Framework Hacks and Core Patches
Patched vendor files, overridden core service providers, composer autoload overrides that shadow framework classes, hand-edited files under vendor/ — these are landmines because composer update erases them and nothing tells you they are gone until production behaves differently. Every core patch you find should add hours to your estimate and lower your confidence interval.
6) Frontend Coupling
An app whose frontend is Blade plus jQuery plus a decade of inline scripts is far more fragile than an app with a clean API boundary. Blade template changes across versions, asset pipeline migrations (Mix → Vite), and Node/build-toolchain upgrades are all in scope.
Apps with a real API contract and a decoupled or Inertia frontend upgrade faster. If you are already there, end-to-end type safety between TypeScript, Vue 3, and Laravel means the compiler catches a whole class of regressions the backend upgrade would otherwise surface in QA.
7) Infrastructure and CI
If your deployment is "SSH in and git pull," you do not have a rollback path, which means every deploy in the upgrade carries full business risk. You will need a pipeline, a staging environment with production-like data, and a tested rollback procedure before the upgrade can proceed safely. That is real budget, though it is budget you keep forever.
If the upgrade coincides with a platform move, read my Laravel AWS migration consultant checklist before combining the two projects — usually you should not.
8) Team Availability
The most commonly ignored driver. If your internal engineers can answer domain questions within a day and do QA passes, the project moves. If the only person who understands the billing logic is on a two-week rotation, calendar time inflates by 50% or more while engineering hours stay flat.
Signal → What It Costs You
Run the audit in the next section and map what you find against this table:
| Signal you find | What it costs you |
|---|---|
| More than 2 major Laravel versions behind | +1 upgrade cycle per version (test, fix, verify, deploy) |
PHP 7.x in composer.json platform config |
Separate PHP phase before any framework work |
| Test suite under 20% coverage | 1.8x–2.5x multiplier; characterization tests come first |
| 5+ abandoned direct dependencies | 20–80 hours each for the ones with no drop-in replacement |
Patched files under vendor/ |
High-variance risk; forces manual diffing and re-patching |
env() called outside config/ |
Breaks under config caching; blocks a standard performance win |
Raw DB:: queries scattered through controllers |
Slower verification; DB behaviour changes are harder to test |
| Laravel Mix, no Vite | Full asset pipeline migration in scope |
| No staging environment | Build staging before the upgrade, not during |
| No CI pipeline | Add pipeline + rollback path as phase zero |
A Working Laravel Upgrade Cost Model
Here is how I turn those drivers into a number. Everything below is a planning range, not a quote. Real quotes require reading the codebase. Use these to sanity-check proposals and to decide whether to fund a paid audit — not to negotiate someone down.
Step 1: Start With Base Hours by Version Distance
Assumes a mid-sized app (roughly 40k–120k lines of PHP), decent test coverage, no core patches.
| Path | Base engineering hours |
|---|---|
| Laravel 12 → 13 | 25 – 60 |
| Laravel 10 → 13 | 70 – 160 |
| Laravel 8 → 13 | 160 – 340 |
| Laravel 6 → 13 | 280 – 550 |
| Laravel 5.x → 13 | 450 – 900+ |
Step 2: Apply Multipliers
Multiply the base by each factor that applies:
| Factor | Multiplier |
|---|---|
| Test coverage under 20% | 1.8x – 2.5x |
| Test coverage 20–40% | 1.3x – 1.5x |
| PHP 7.x → 8.4 jump included | 1.3x – 1.6x |
| 5+ abandoned direct dependencies | 1.2x – 1.5x |
| Known patches to vendor/core | 1.2x – 1.4x |
| Blade + jQuery + Mix frontend | 1.2x – 1.4x |
| No CI/CD or staging environment | +60 – 120 flat hours |
Step 3: Convert to Money
Blended senior Laravel rates in 2026 vary enormously by market. Reasonable planning brackets:
- Offshore/nearshore independent senior: $40 – $75/hr
- Established boutique agency (US/EU): $110 – $200/hr
- Enterprise consultancy: $200 – $350/hr
Three Worked Examples
Example A — SaaS on Laravel 10, 55% coverage, CI in place, Inertia frontend. Base 70–160 hours, no multipliers. Roughly 100–170 hours. At $65/hr that is $6,500 – $11,000; at $150/hr, $15,000 – $25,000. This is the profile you want to be in, and it is the argument for upgrading annually.
Example B — Internal ops app on Laravel 8, ~15% coverage, PHP 8.0, Blade/jQuery, no staging. Base 160–340. Apply 2.0x (coverage), 1.3x (frontend), plus 90 flat hours for pipeline and staging. Roughly 500 – 980 hours. At $65/hr, $33,000 – $64,000; at $150/hr, $75,000 – $147,000. Note how the coverage multiplier, not the version distance, dominates.
Example C — Revenue-critical marketplace on Laravel 5.8, PHP 7.4, no tests, three patched vendor packages. Base 450–900. Apply 2.3x (coverage), 1.5x (PHP), 1.3x (patches). You are into 2,000 – 4,000+ hours. At that scale the conversation is no longer "upgrade or not" — it is the scorecard further down this post, and almost certainly a strangler-fig program rather than a single upgrade project.
The pattern worth internalising: hours scale with neglect, not with version numbers. A team that upgrades every year pays a small annual premium. A team that waits six years pays a multiple of the sum of those premiums, plus the security exposure in between.
Timeline Expectations: Why Calendar Time Exceeds Engineering Time
Clients routinely divide total hours by 40 and assume that is the schedule. It never is. Upgrades have hard serialization: you cannot test version 10 until version 9 is stable, and you cannot get sign-off on Friday's changes until a human uses the app on Monday.
| App size | Engineering hours | Realistic calendar |
|---|---|---|
| Small (single dev, 1–2 versions behind) | 40 – 120 | 2 – 4 weeks |
| Medium (3–4 versions behind, partial tests) | 300 – 700 | 8 – 16 weeks |
| Large (5+ versions, low coverage, integrations) | 1,000 – 3,000 | 5 – 12 months, phased |
Calendar time runs 1.5x–3x engineering time because of:
- Sequential version hops. Each hop needs its own test-fix-verify-deploy loop.
- Stakeholder verification windows. Someone in finance has to confirm the invoice totals are still right. That takes days, not hours.
- Third-party lead times. A payment provider's sandbox, an SSO vendor's certificate rotation, a partner API's compatibility confirmation.
- Feature freeze negotiation. You rarely get a full freeze. Merging ongoing feature work into an upgrade branch is real, recurring cost.
- Deploy windows. Regulated or high-traffic businesses deploy on a schedule, not on demand.
Budget these as facts of life, not as slippage.
Scope It Yourself in an Afternoon
Before you pay anyone for an audit, run these. Two to four hours of your team's time produces most of the inputs to the model above, and it makes every vendor conversation sharper.
Establish the Baseline
# What are we actually running?
php artisan about
# Framework and PHP versions from the source of truth
php -r 'echo json_decode(file_get_contents("composer.json"))->require->php, PHP_EOL;'
php -v
# Is a platform override lying to you about the real PHP version?
composer config platform
That last one matters more than people expect. A platform.php override in composer.json pins dependency resolution to a version you may not actually be running in production, which hides incompatibilities until deploy time.
Measure Version Distance and Blockers
# Direct dependencies only - the ones you chose and own
composer outdated --direct
# Flag abandoned packages explicitly
composer audit --abandoned=report
# The single most useful command in an upgrade audit:
# it tells you exactly which packages block your target
composer why-not laravel/framework ^13.0
composer why-not output is effectively your blocker list. Print it and put it in the scoping document. Each unresolved line is a package you must upgrade, replace, fork, or absorb.
Get a Static Analysis Baseline
PHPStan with Larastan gives you a defensible, countable measure of code health. The error count at level 5 is a proxy for how much undiscovered breakage is waiting.
composer require --dev phpstan/phpstan larastan/larastan
# phpstan.neon
includes:
- vendor/larastan/larastan/extension.neon
parameters:
level: 5
paths:
- app
- config
- database
- routes
treatPhpDocTypesAsCertain: false
# Count the errors - this number is your scoping signal
./vendor/bin/phpstan analyse --no-progress | tail -5
# Freeze existing errors so new code must be clean from today
./vendor/bin/phpstan analyse --generate-baseline
Rough interpretation for an app of 50k–100k lines: under 300 errors at level 5 is healthy; 300–1,500 is normal for a legacy app; over 3,000 means expect surprises and widen your contingency.
Estimate the Automatable Portion with Rector
Rector plus rector-laravel will not do the upgrade for you, but a dry run tells you how much of the work is mechanical (cheap) versus semantic (expensive).
composer require --dev rector/rector driftingly/rector-laravel
<?php
// rector.php
declare(strict_types=1);
use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\LevelSetList;
use RectorLaravel\Set\LaravelLevelSetList;
use RectorLaravel\Set\LaravelSetList;
return RectorConfig::configure()
->withPaths([
__DIR__ . '/app',
__DIR__ . '/config',
__DIR__ . '/database',
__DIR__ . '/routes',
__DIR__ . '/tests',
])
->withSets([
// PHP language-level upgrades - use the highest level
// constant available in your installed Rector version
LevelSetList::UP_TO_PHP_84,
// Laravel framework upgrades, cumulative to your target
LaravelLevelSetList::UP_TO_LARAVEL_120,
LaravelSetList::LARAVEL_CODE_QUALITY,
LaravelSetList::LARAVEL_IF_HELPERS,
])
->withImportNames(removeUnusedImports: true);
# Never run this without --dry-run first
./vendor/bin/rector process --dry-run
# Rough count of files Rector believes it can change automatically
./vendor/bin/rector process --dry-run | grep -c '^ *[0-9]*) '
If Rector claims a large share of your changed files, the mechanical portion is big and your estimate should trend to the low end of the range. If it claims very little, most of the work is human judgement and you should trend high.
The Ten-Minute Risk Scan
Drop this in scripts/upgrade-scan.sh and run it from the project root.
#!/usr/bin/env bash
# scripts/upgrade-scan.sh - rough risk signals for Laravel upgrade scoping
set -uo pipefail
echo "=== Laravel Upgrade Risk Scan ==="
echo -n "Abandoned direct packages: "
composer audit --abandoned=report --format=plain 2>/dev/null \
| grep -ci 'abandoned' || echo 0
echo -n "Direct DB:: queries in app code: "
grep -rn --include='*.php' -E 'DB::(select|statement|raw|table|insert|update|delete)' app/ \
| wc -l
echo -n "env() calls outside config/ (breaks config caching): "
grep -rn --include='*.php' 'env(' app/ routes/ database/ 2>/dev/null | wc -l
echo -n "Modified or patched vendor files: "
git status --porcelain vendor/ 2>/dev/null | wc -l
echo -n "String-based route actions (pre-Laravel 8 style): "
grep -rn --include='*.php' -E "Route::[a-z]+\([^)]*'[A-Za-z]+Controller@" routes/ | wc -l
echo -n "Blade views: "
find resources/views -name '*.blade.php' 2>/dev/null | wc -l
echo -n "Test files: "
find tests -name '*Test.php' 2>/dev/null | wc -l
echo -n "App classes: "
find app -name '*.php' 2>/dev/null | wc -l
echo
echo "Ratio of test files to app classes is a crude but useful coverage proxy."
echo "Below 1:10 means the characterization-test multiplier applies."
For a real coverage number rather than a proxy:
# Requires Xdebug or PCOV
XDEBUG_MODE=coverage php artisan test --coverage --min=0
If you want this scan done faster and more thoroughly, AI tooling is genuinely good at this specific job — mapping unfamiliar code and cataloguing risk. I wrote up the workflow in my practitioner's guide to Claude Code on legacy codebases, and the broader pattern in how developers are modernizing legacy codebases with Claude Code.
Laravel Upgrade vs Rewrite: An Honest Scorecard
Every engineer who inherits a legacy app wants to rewrite it. Almost every one of them is wrong, and I include my younger self in that.
The reason is not sentimentality about old code. It is that an upgrade preserves a decade of encoded business rules — the edge cases, the tax exceptions, the one client whose contract requires different invoice rounding — while a rewrite requires you to rediscover every one of them, usually by shipping bugs to customers who already trusted you. Rewrites also produce zero customer-visible value for their entire duration, which is a brutal thing to defend in month nine.
The Weighted Scorecard
Score each criterion 1 (favours upgrade) to 5 (favours rewrite), multiply by weight, and total.
| Criterion | Weight | Score 1 (upgrade) | Score 5 (rewrite) |
|---|---|---|---|
| Business logic value in existing code | 25% | Deep, undocumented, correct | Thin CRUD, well understood |
| Data model quality | 20% | Sound, normalized, extendable | Fundamentally wrong shape |
| Framework fit | 15% | Still Laravel-shaped | Fighting the framework daily |
| Team knowledge of current system | 15% | Original team present | Nobody left who knows it |
| Requirements stability | 10% | Product direction unchanged | Product is pivoting anyway |
| Regulatory/compliance pressure | 10% | None | Mandated re-architecture |
| Cost of continued operation | 5% | Manageable | Bleeding money monthly |
Interpretation:
- Under 2.0 — Upgrade. Full stop. The math is not close.
- 2.0 to 3.2 — Strangler fig. This is where most genuinely troubled apps land.
- Above 3.2 — A rewrite may be defensible. Prove it with a scoped spike before committing budget.
When a Rewrite Genuinely Wins
I have seen it be the right call, but only under specific conditions:
- The data model is wrong at the root. If the core entity relationships were modelled incorrectly and years of features are built on that mistake, migrating the schema is the project either way — and you may as well get a clean application out of it.
- The product is pivoting. If more than half the existing features are being retired, you are not preserving business value, you are preserving dead weight.
- It is not really a Laravel app. Some "Laravel" codebases are a pre-framework PHP application wearing a Laravel folder structure, with routing, auth, and persistence all bypassed. There is nothing to upgrade.
- The app is genuinely small. Under roughly 15k lines with a clear domain, a rewrite can be cheaper than archaeology. Be ruthlessly honest about the line count.
- Compliance mandates architecture change. Data residency, tenant isolation, or auditability requirements that the current design cannot satisfy at any price.
Absent one of those, assume the rewrite estimate you have been given is 2x–3x low. That is the historical average, and there is no reason to believe your project is the exception.
The Strangler Fig Middle Path
For most apps scoring in the middle, the right answer is neither. Legacy Laravel modernization works best incrementally: you upgrade the framework to a supported version to stop the bleeding, then extract high-value domains into new services or modules behind a routing layer while the legacy core keeps serving revenue.
Strangler fig wins specifically when:
- The app must keep earning money throughout — no freeze is available
- A few well-defined domains hold most of the pain (billing, search, reporting)
- You want optionality: each extracted piece is independently valuable and independently abandonable
- Stakeholders need visible progress every quarter, not a promise at month twelve
It is more total engineering hours than a clean upgrade and fewer than a rewrite, but it is the only one of the three where you can stop halfway and still be better off than when you started. That optionality is worth paying for. If the extracted pieces are APIs, apply the contract and versioning discipline from my Laravel API development best practices from day one — the boundary is the whole point.
How to Sequence a Laravel Upgrade Safely
The sequencing below is what keeps the estimate honest. Skipping steps is how a 300-hour project becomes a 700-hour one.
- Pin everything first. Commit
composer.lockand your JS lockfile, capture exact PHP and extension versions from production, and reproduce that environment locally and in CI. You cannot measure change against a moving baseline. - Build the test harness before touching the framework. CI that runs on every push, a staging environment with anonymized production-shaped data, and a rollback procedure you have actually executed at least once.
- Write characterization tests for revenue paths. Not aspirational tests — tests that document what the system does today, including behaviour you consider wrong. Checkout, billing, auth, permissions, exports, and any nightly job that touches money.
- Upgrade PHP first, within your current Laravel version. This isolates language-level breakage from framework-level breakage. Debugging one class of failure at a time is dramatically faster than debugging both.
- One major Laravel version at a time, one PR per hop. Merge and deploy each hop before starting the next. A branch that spans three versions cannot be reviewed or reverted meaningfully.
- Put risky behavioural changes behind feature flags. Where an upgrade changes semantics — serialization formats, date handling, cache key structure — flag it so you can toggle at runtime instead of redeploying under pressure.
- Deploy with a real strategy. Blue/green or rolling, health checks that actually fail the deploy, and
php artisan queue:restartin the pipeline so workers do not keep executing pre-upgrade code. - Watch the right things after cutover. Error rate, p95 latency, queue depth, failed jobs, and one business metric such as completed checkouts. If any of them move the wrong way, roll back and diagnose — do not fix forward at 11pm.
Two upgrade-adjacent notes. First, do not bundle a hosting migration into the same project; if AWS is on the roadmap, sequence it separately using the AWS cost optimization audit checklist once the code is stable. Second, resist performance work mid-upgrade. Save Octane and query optimization for after you are on a supported version — they are cheaper and safer then, and they muddy your regression signal if done during.
What to Budget Beyond the Code
Engineering hours are typically 60–70% of the true cost. The rest:
- QA and regression testing — 15–25% of engineering hours. Someone has to click through the app after every version hop. If you have no QA function, this lands on your engineers or your customers.
- Stakeholder verification time — 20–60 hours. Finance confirms the numbers. Ops confirms the workflows. Support confirms the admin panel. This is real payroll, and it is on the critical path.
- Staging and parallel infrastructure — 1–3 months of duplicated environment cost. Plus data anonymization work if you handle personal data.
- Post-upgrade stabilization window — 2–4 weeks of reduced feature velocity. Budget explicitly for the long tail of edge cases that only production traffic finds. Teams that skip this line item are the ones who conclude the upgrade "failed."
- Contingency — 20% if you did the audit, 35–40% if you did not. Anyone quoting an upgrade with zero contingency is either padding the base rate or has not read the code.
- Ongoing maintenance — 4–8 hours per month, plus one planned upgrade sprint per year. This is the line that determines whether you are back here in 2032. Laravel ships a major every Q1 with an 18-month bug-fix window; one modest sprint annually keeps you permanently in the cheap column of the table above.
Red Flags in Upgrade Quotes
I get asked to review vendor proposals fairly often. These are the things that make me tell a client to slow down:
- A fixed price with no paid discovery. Nobody can price a legacy upgrade from a call and a repo skim. A fixed price without an audit means the risk is priced in as padding, or it is about to become a change-order fight.
- No mention of tests. If the proposal does not say who writes the characterization tests and when, they intend to verify by clicking. That does not scale past the first version hop.
- "We'll go straight to Laravel 13." Skipping majors is a red flag on any path longer than two versions. Ask explicitly how many intermediate deploys are planned.
- No rollback plan in the document. If rollback is not written down, it does not exist.
- The rewrite pitch on first contact. A vendor who recommends a rewrite before reading the code is selling the larger contract, not the right answer.
- A timeline with no calendar/engineering distinction. "400 hours, so 10 weeks" tells you they have not accounted for verification windows or feature-branch merges.
- Nothing about handover. Docs, runbooks, and a maintenance plan should be deliverables. Otherwise you have swapped framework debt for vendor dependency.
- No named engineers. Ask who is actually doing the work and what else they are on. Senior-priced proposals staffed by juniors are common. My senior Laravel developer interview questions work equally well for vetting an agency's proposed team.
Good sign to look for: the proposal contains a table of assumptions and states explicitly what invalidates the estimate. That is what a serious estimate looks like.
Frequently Asked Questions
How much does it cost to upgrade Laravel? For a mid-sized app one or two versions behind with reasonable tests, plan on 40–170 hours — roughly $3,000–$25,000 depending on rate. For an app four or more versions behind with low coverage, 500–1,000 hours and $35,000–$150,000 is a realistic planning range. Version distance sets the base; test coverage sets the multiplier. These are ranges for budgeting, not quotes.
How long does a Laravel upgrade take? Two to four weeks for a small, well-tested app. Eight to sixteen weeks for a medium app three or four versions behind. Five to twelve months, phased, for a large legacy system. Calendar time runs 1.5x–3x engineering time because version hops are sequential and stakeholder verification cannot be parallelized.
Is it worth upgrading Laravel? If you are on a version past its security window — Laravel 11 and below as of September 2026 — yes, and the framing is risk rather than ROI: you are running unpatched code in production. If you are on Laravel 12, you have runway until February 2027, so plan it rather than rushing it. The strongest argument is compounding: annual upgrades cost a fraction of a once-a-decade one.
Should I rewrite my Laravel app instead of upgrading? Usually no. Rewrites typically come in at 2x–3x the estimate and deliver no customer value until they ship. Rewrite genuinely wins when the data model is wrong at the root, when the product is pivoting away from most existing features, when it is not really a Laravel app underneath, or when compliance mandates a new architecture. Score it on the weighted scorecard above before committing budget.
Can we skip Laravel versions to save money? No, and attempting it costs more than doing it properly. Laravel's upgrade guides assume you are coming from the immediately previous major. Skipping means compounding breaking changes with no documentation, and no clean intermediate state to deploy or revert to.
Do we need to stop feature development during a Laravel upgrade? A full freeze is ideal and rarely realistic. The workable compromise is a freeze on architectural and database-schema changes, with small feature work continuing on short-lived branches rebased frequently onto the upgrade branch. Budget explicit hours for merge conflict resolution — on a multi-month project it is a meaningful line item, not a rounding error.
What if our app has no tests at all? Then the first phase of the project is writing characterization tests for revenue-critical paths, and that is 30–40% of total effort. It is not optional. Without them you cannot distinguish "the upgrade broke this" from "this was always broken," and every version hop becomes a multi-day manual QA cycle.
Key Takeaways
- Laravel upgrade cost is driven by neglect, not version numbers. Test coverage is the single largest multiplier — a 2x swing on otherwise identical codebases.
- Use the model as a sanity check, not a quote. Base hours by version distance, then multipliers for coverage, PHP jump, dead packages, core patches, and frontend coupling.
- Calendar time is 1.5x–3x engineering time. Sequential version hops and stakeholder verification are structural, not slippage.
- Run the audit yourself first.
composer why-not laravel/framework ^13.0, a PHPStan baseline, and a Rector dry run give you most of the scope in an afternoon. - Rewrite is almost always more expensive than it looks. Score it honestly; the strangler-fig middle path wins for most troubled apps because you can stop halfway and still be ahead.
- Budget beyond the code. QA, stakeholder time, staging, a stabilization window, 20–40% contingency, and one planned upgrade sprint per year so you never repeat this.
The cheapest Laravel upgrade is the one you do next year, not the one you defer until the security advisory arrives. If you are somewhere on this spectrum and want a concrete number instead of a range, I run fixed-scope upgrade audits that produce a blocker list, a risk-scored inventory, a phased plan, and a defensible estimate you can take to your board — whether or not you hire me for the implementation.
Get in touch about an upgrade audit, or review my Laravel and PHP services to see what a full engagement covers.
Related reading:
- Migrate Legacy Laravel Apps: 14 Years of Lessons
- Hire a Laravel AWS Migration Consultant: Scope, Timeline, and Red Flags
- Claude Code for Legacy Codebases: A Practitioner's Guide
- Laravel Database Optimization
- Senior Laravel Developer Interview Questions
External resources:

Richard Joseph Porter
Senior Laravel Developer with 14+ years of experience building scalable web applications. Specializing in PHP, Laravel, Vue.js, and AWS cloud infrastructure. Based in Cebu, Philippines, I help businesses modernize legacy systems and build high-performance APIs.
Need Help Upgrading Your Laravel App?
I specialize in modernizing legacy Laravel applications with zero downtime. Get a free codebase audit and upgrade roadmap.
Related Articles
PHP 8.3 to 8.5 for Laravel Teams: The Upgrade Before the Upgrade
Upgrade PHP for Laravel the right way: a staged 8.3 to 8.4 to 8.5 path, the PHP 8.4 breaking changes that bite, CI matrix, canary rollout, and rollback.
Upgrading to Laravel 13: What Changed and What Breaks
A practical Laravel 13 upgrade guide: the breaking changes that actually bite, paths from Laravel 10, 11, and 12, an audit checklist, and realistic timelines.
Hire a Laravel AWS Migration Consultant: Scope, Timeline, and Red Flags
A buyer-intent guide for founders and CTOs planning a Laravel/PHP migration to AWS, including engagement scope, realistic timelines, and how to avoid expensive mistakes.