Skip to content
ExponaBLOG
PHP & LARAVEL DEVELOPMENT · DAY 076 / 100

Upgrading Laravel versions: patterns, pitfalls and fixes

Stay current without pain.

Expona Admin6 min read

Upgrading Laravel versions: patterns, pitfalls and fixes

Laravel releases new major versions roughly every six months, bringing performance improvements, new features, and security patches. Staying current keeps your application secure and maintainable, but the upgrade process can feel daunting if you haven't done it before or if you're jumping multiple versions at once. We'll walk through the proven patterns that make upgrading Laravel versions safe and predictable, from reading the upgrade guide to running your test suite with confidence.

Read the upgrade guide — Each major version lists breaking changes

Before you touch a single line of code, read the official Laravel upgrade guide for your target version. Laravel's documentation team does an excellent job documenting every breaking change, deprecation, and new requirement. This is your roadmap and your insurance policy rolled into one.

When upgrading from Laravel 10 to Laravel 11, for example, the guide lists that the default HTTP client timeout was reduced from 30 seconds to 0 (infinite), that the bootstrap/app.php file structure changed, and that several helper functions were removed or moved. Skipping this step is how most painful upgrades start. You end up discovering breaking changes in production logs instead of in your test environment.

Keep a text file or notebook open as you read. Jot down:

  • Dependencies that must be updated to specific versions
  • Configuration files that changed structure
  • Methods or classes marked as deprecated
  • New requirements (PHP version, extensions)
  • Features you're using that changed behavior

Then cross-reference your application against that list. If you use Laravel Passport and you're upgrading to a version that changed its API, you need to know that before you start. The guide makes it visible; ignorance never makes an upgrade smoother.

Use Laravel Shift — Automated upgrade pull requests

Laravel Shift is an automated upgrade service that analyzes your codebase and generates a pull request with most of the mechanical changes already done. It's not perfect—no tool is—but it handles the repetitive work so you can focus on behavioral changes and testing.

Here's a typical workflow:

  1. Push your main branch to GitHub (Shift requires GitHub access)
  2. Visit shift.laravel.com and authenticate
  3. Select your repository and target Laravel version
  4. Shift analyzes your code and opens a pull request within minutes
  5. Review, test, and merge the PR

Shift typically handles:

  • Composer.json updates (Laravel, dependencies)
  • Config file merges (new keys, removed keys)
  • Namespace updates
  • Method signature changes on core classes
  • Database migration compatibility
  • Deprecated function replacements

For a small to medium application, Shift often resolves 70–90% of the upgrade work. For larger codebases with custom packages or deeply integrated third-party services, expect more manual work. But even then, the PR gives you a clear starting point and a checklist of what changed.

One team we know upgraded a Laravel 9 SaaS application to Laravel 11 in a single afternoon using Shift. The PR had 47 commits, touched 120 files, and resolved namespace changes, config merges, and deprecation fixes automatically. The remaining work was testing and verifying business logic in the new version—much faster than doing all of it by hand.

Tests first — A good test suite makes upgrades safe

This is non-negotiable: before you upgrade, your test suite must be green and comprehensive. A weak test suite doesn't protect you during upgrades; it gives you false confidence. If you have 30% coverage and the tests pass, that just means you haven't tested the 70% that might be broken.

An ideal test suite for upgrade safety includes:

  • Unit tests for business logic (calculations, validations, state changes)
  • Feature tests for API endpoints and critical user workflows
  • Integration tests for database queries and external service calls
  • Browser tests (if applicable) for JavaScript-heavy pages

Once you've applied the upgrade changes (manually or via Shift), run your test suite in the new version. Tests will fail in three ways:

  1. Test code needs updating: The testing API changed, mock signatures changed, or assertions were renamed. This is mechanical and usually quick to fix.
  2. Application code is broken: A method was removed, a class was renamed, or behavior changed. Your tests catch this, and you fix it.
  3. Logic is subtly wrong: The upgrade succeeded, tests still pass, but the behavior isn't what you expected. This is rare if your test suite is thorough, but it's why you also do manual testing.

Here's a simplified example. Suppose you have a test for a payment service:

php
public function test_payment_timeout_respects_config()
{
    config(['services.payment.timeout' => 5]);
    
    $response = Http::timeout(5)->get('https://api.payment.example/charge', [
        'amount' => 1000,
    ]);
    
    $this->assertTrue($response->successful());
}

If Laravel 11 changed how timeouts work, this test might fail—and that's a good thing. You'll catch it before your users do. You'll update the test to match the new API, or you'll adjust your application code to work with the new behavior.

Run your full test suite after the upgrade, including:

php
php artisan test --parallel

Use parallel execution if you have many tests. It's faster and closer to real-world load. If tests fail, fix them one by one, and understand why each one is failing. Don't just make tests pass; make sure they still test what you intended.

Upgrade often — Small yearly upgrades are easier than big jumps

The best way to make upgrading easy is to do it often. Upgrade each new minor or major version shortly after it's released, while the codebase hasn't drifted too far. If you upgrade every six months or yearly, each upgrade is a small change. If you skip three or four versions, you're essentially rewriting parts of your application.

Consider two scenarios:

  • Team A upgrades Laravel 9 → 10 → 11 over 18 months, each upgrade taking a day or two.
  • Team B stays on Laravel 9 for two years, then upgrades to 11 all at once, taking a week.

Team A's total effort is lower, their code is always recent, and they learn the framework's evolution incrementally. Team B's single upgrade is massive; they're also more likely to hit subtle bugs or compatibility issues with third-party packages that have since moved on.

Our recommendation: schedule an upgrade sprint every 6–9 months. Make it part of your regular cadence, like paying technical debt. Allocate 2–5 days depending on your application size. Use it as an opportunity to review and refactor aging code. Your future self will thank you.

Common mistakes

Upgrading without reading the guide: "It's just a minor version bump, right?" Wrong. Even patch releases can include breaking changes. Read the guide every time.

Trusting Shift 100%: Shift is powerful, but it's not a silver bullet. You must review every change, run tests, and manually verify critical features. Treat it as a first pass, not the final answer.

Merging without testing in production-like conditions: Your local Docker environment isn't production. Before merging to main, deploy to a staging environment that mirrors production as closely as possible. Run smoke tests, load tests, and manual testing there.

Skipping minor versions: You see Laravel 10 is available, but you're still on 8. Skipping to 10 directly is tempting but risky. Upgrade 8 → 9 → 10 if you can, or at minimum read the guides for every skipped version and account for all their breaking changes.

Not updating dependencies: Your application depends on third-party packages. When you upgrade Laravel, those packages might also need updates. Check their changelogs and upgrade them alongside Laravel. A package that worked on Laravel 9 might have a bug or incompatibility on Laravel 10.

Key takeaways

  • Read the official upgrade guide for your target version before writing any code. It lists every breaking change and new requirement.
  • Use Laravel Shift to automate mechanical changes, but review the PR thoroughly and don't merge blindly.
  • A comprehensive test suite is your safety net during upgrades. Green tests in the new version give you confidence.
  • Upgrade frequently—every 6–9 months—rather than letting versions pile up. Small upgrades are faster and safer than big jumps.
  • Always test in a staging environment that matches production before deploying an upgrade to live users.
  • Remember that third-party packages must also be compatible with your target Laravel version. Update them as part of the upgrade cycle.
ShareXLinkedInReddit

Found this useful? Support the writing.

Buy me a coffee
Written by
Expona Admin
Site administrator

Comments

Loading comments…

Leave a comment

Comments are reviewed before they appear. Be kind and stay on topic.

Related articles