Laravel v13.5.0 adds first-class Redis Cluster support for the queue driver and concurrency limiter, fixing CROSSSLOT errors on AWS ElastiCache Serverless and other Redis Cluster deployments. It also completes #[Delay] attribute coverage for queued mailables, adds Controller Middleware attribute inheritance, expands enum support across manager classes, and includes a number of bug fixes.
- First-class Redis Cluster support for Queue and ConcurrencyLimiter
#[Delay]attribute now works on queued mailables- Controller Middleware attributes are inherited by child controllers
- Enum support expanded across Cache, Mail, Auth, and other manager drivers
- Closure values accepted in
updateOrCreateandfirstOrNew - New
Cache::handleUnserializableClassUsing()hook for detecting broken cache values - Fix for
ShouldBeUniqueUntilProcessingjobs releasing locks they don't own
What's New
First-Class Redis Cluster Support for Queue and ConcurrencyLimiter
When using AWS ElastiCache Serverless (Valkey) or any Redis Cluster deployment, Laravel's Redis queue and ConcurrencyLimiter previously failed with CROSSSLOT errors. The queue's Lua scripts operate across multiple keys — queues:default, queues:default:reserved, and queues:default:notify — that hash to different cluster slots, which Redis Cluster prohibits in a single command.
Laravel now automatically wraps queue names in Redis hash tags when the connection is a cluster, ensuring all related keys hash to the same slot:
queues:{default} → slot for "default"queues:{default}:delayed → slot for "default"queues:{default}:reserved → slot for "default"queues:{default}:notify → slot for "default"
Different queues ({emails}, {notifications}) still distribute across the cluster naturally. The public getQueue() method is unchanged, so existing integrations that consume queue names continue to see the same format as before, while Redis operations themselves use cluster-safe keys. Non-cluster users are unaffected.
The ConcurrencyLimiter receives the same treatment — slot keys are now wrapped in hash tags on cluster connections, so the mget Lua script no longer crosses slots.
On phpredis 5.3.2 and newer, the PhpRedis cluster connector also gains ACL auth support and max_retries, backoff_algorithm, backoff_base, and backoff_cap options to improve compatibility with ElastiCache Serverless scaling behavior.
Pull Request: #59533 by @timmylindh
#[Delay] Attribute Support on Queued Mailables
The #[Delay] attribute support added across queued event listeners, jobs, and notifications in v13.4.0 now applies to queued mailables too. Previously, mailables only checked the $delay property and ignored the attribute entirely.
use Illuminate\Queue\Attributes\Delay; #[Delay(30)]class WelcomeEmail extends Mailable implements ShouldQueue{ // Now correctly delayed by 30 seconds when queued}
The $delay property still takes precedence when explicitly set, matching the behavior of the other dispatchers.
Pull Request: #59580 by @sumaiazaman
Controller Middleware Attribute Inheritance
The #[Middleware] attribute on a base controller is now inherited by child controllers. Previously, child controllers ignored middleware attributes defined on their parent, requiring duplication across each class.
use Illuminate\Routing\Attributes\Middleware; #[Middleware('auth')]#[Middleware('log:api')]abstract class AdminBaseController extends Controller{ // Common admin logic} class AdminController extends AdminBaseController{ public function index() { // Inherits 'auth' and 'log:api' middleware from the parent }}
Attributes are collected in parent-to-child order, consistent with how PHP resolves class hierarchies.
Pull Request: #59597 by @niduranga
Enum Support Expanded Across Manager Classes
Enum support has been added to several manager classes that were previously missing it:
CacheManager — store(), driver(), memo(), forgetDriver(), purge(), and setDefaultDriver() now accept a UnitEnum:
enum CacheStore: string{ case Redis = 'redis'; case Array = 'array';} Cache::store(CacheStore::Redis)->put('key', 'value');
MailManager — mailer(), driver(), and purge() now accept enums.
AuthManager — guard(), shouldUse(), and setDefaultDriver() now accept enums.
Laravel also added enum support to the base Manager::driver() method, extending the same pattern to other manager classes that inherit from it.
This continues the enum-support wave that already covered QueueManager, LogManager, DatabaseManager, FilesystemManager, RedisManager, and BroadcastManager.
Pull Requests: #59637, #59645, #59646, #59659 by @yousefkadah and @scabarcas17
Closure Values in updateOrCreate and firstOrNew
updateOrCreate and firstOrNew now accept a Closure for the $values argument, completing the lazy-evaluation pattern introduced in v13.x for firstOrCreate and createOrFirst. This allows you to defer expensive operations — like geocoding or API calls — until you know the record actually needs to be created or updated:
$location = Location::updateOrCreate( ['address' => $address], fn () => ['coordinates' => Geocoder::resolve($address)],);
The closure is called exactly once per method call. On firstOrNew, the closure is never invoked when the record already exists.
Pull Request: #59647 by @yousefkadah
Detect Unserializable Cache Values
A new Cache::handleUnserializableClassUsing() hook lets you register a callback that runs when a cache value deserializes to __PHP_Incomplete_Class — which can happen when the serializable_classes config is in use and a class is missing from the allow-list.
Cache::handleUnserializableClassUsing(function (string $key, ?string $class): void { if (app()->isProduction()) { Log::warning("Cache hit [{$key}] returned unserializable class [{$class}]"); return; } throw new RuntimeException("Cache hit [{$key}] returned unserializable class [{$class}]");});
No handler is registered by default, so this is purely opt-in with no behavior changes for existing applications.
Pull Request: #59630 by @jackbayliss
Other Fixes and Improvements
Queue:
- Fixed
ShouldBeUniqueUntilProcessingjob retries releasing locks they don't own (#59567 by @kohlerdominik)
Redis:
- Normalized phpredis SSL context options for single and cluster connections (#59569 by @timmylindh)
Auth:
- Fixed
redirectUsersTo()overwriting theredirectGuestsTo()callback (#59633 by @timmylindh) - Fixed a loose comparison false positive in
NotPwnedVerifierwith magic hash passwords (#59644 by @scabarcas17)
Testing:
- Memoized the result of
TestCase::withoutBootingFramework()to avoid redundant work (#59610 by @cosmastech)
Other:
- Fixed a custom driver binding bug in Manager classes (#59614 by @ollieread)
- Added
spatie/forkto Composer suggestions for concurrency support (#59660 by @jnoordsij) - Moved the
Scopeinterface@templatefrom method-level to class-level to fix an LSP violation (#59675 by @kayw-geek)
References