Skip to main content

Introduction

Laravel 10 was released on February 14, 2023. This guide walks through the upgrade from Laravel 9.x to 10.x.
Estimated time to upgrade is about 10 minutes. Actual impact from breaking changes depends on your app’s size and features you use.

Automated upgrades with Laravel Shift

You can automate the upgrade with Laravel Shift. Shift updates dependencies and configuration files automatically.

Changes by impact level

Impact: high

  • Dependency updates
  • minimum-stability update

Impact: medium

  • Database expression changes
  • Removal of the model $dates property
  • Monolog 3
  • Redis cache tags
  • Service mocking changes
  • The language directory

Impact: low

  • Closure validation rule messages
  • The after method on form requests
  • Public path binding
  • QueryException constructor
  • Rate limiter return value
  • Removal of Redirect::home
  • Removal of Bus::dispatchNow
  • The registerPolicies method
  • ULID columns

Upgrade steps

Update dependencies

Impact: high Update the following dependencies in composer.json.
If you use these packages, update them too.
If you’re using PHPUnit 10, also update:
With PHPUnit 10, remove the processUncoveredFiles attribute from the <coverage> section of phpunit.xml.
Then install dependencies:
For Sanctum 2.x → 3.x, also consult the Sanctum 3.x upgrade guide.

Update minimum-stability

Impact: high Update minimum-stability in composer.json to stable. Since stable is the default, you can also remove this setting altogether.

PHP version requirement

Impact: high Laravel 10 requires PHP 8.1.0 or later and Composer 2.2.0 or later.

Breaking changes

Application

Public path binding

Impact: low If you customize the public path by binding path.public in the container, switch to Illuminate\Foundation\Application’s usePublicPath method.

Authorization

The registerPolicies method

Impact: low The framework now calls AuthServiceProvider’s registerPolicies method automatically. You can remove the manual call from boot.

Cache

Redis cache tags

Impact: medium Cache::tags() is recommended only for apps using Memcached. If you use Redis as your cache driver, consider migrating to Memcached.

Database

Database expression changes

Impact: medium Database expressions produced by DB::raw have been rewritten. To get the raw string value of an expression, use the getValue(Grammar $grammar) method. Casting to (string) no longer works.
Most end-user apps aren’t affected, but if you cast database expressions to string, updates are required.

QueryException constructor

Impact: very low The Illuminate\Database\QueryException constructor now takes a connection name string as the first argument. If you manually throw this exception, adjust the code.

ULID columns

Impact: low When you call the ulid method in a migration without arguments, the column name is now ulid. In previous releases, calling it without arguments incorrectly created a column named uuid.

Eloquent

The model $dates property

Impact: medium The deprecated $dates property on Eloquent models has been removed. Use the $casts property instead.

Localization

The language directory

Impact: none Existing apps aren’t affected, but new Laravel application skeletons no longer include the lang directory by default. Publish it via an Artisan command if needed.

Logging

Monolog 3

Impact: medium Laravel’s Monolog dependency has been updated to Monolog 3.x. If you use Monolog directly in your app, review the Monolog upgrade guide. If you use third-party logging services like BugSnag or Rollbar, you may need to upgrade to versions that support both Monolog 3.x and Laravel 10.x.
Monolog 3.x changes are documented in the Monolog 3.x upgrade guide.

Queue

Removal of Bus::dispatchNow

Impact: low The deprecated Bus::dispatchNow and dispatch_now methods have been removed. Use Bus::dispatchSync and dispatch_sync.

Routing

Middleware aliases

Impact: optional In new Laravel apps, App\Http\Kernel’s $routeMiddleware property was renamed to $middlewareAliases. Applying it to existing apps is optional.

Rate limiter return value

Impact: low When you call RateLimiter::attempt, the return value of the provided closure is now returned as-is. If you return nothing or null, true is returned.

Removal of Redirect::home

Impact: very low The deprecated Redirect::home method has been removed. Redirect to a named route explicitly.

Testing

Service mocking

Impact: medium The deprecated MocksApplicationServices trait has been removed from the framework. It provided test methods like expectsEvents, expectsJobs, and expectsNotifications. If you use these methods, migrate to Event::fake, Bus::fake, and Notification::fake respectively.

Validation

Closure validation rule messages

Impact: very low In closure-based custom validation rules, calling $fail multiple times now appends messages to an array instead of overwriting. Also, the $fail callback now returns an object. If you type-hint the return value of a validation closure, update it.

The after method on form requests

Impact: very low Laravel now reserves an after method on form requests. If your form request defines an after method, rename it or migrate to the new “after validation” feature.

Summary

Laravel 10 involves relatively small changes, and the upgrade can be completed quickly.

References

Last modified on July 13, 2026