Laravel 13.6.0 is a small feature release with a few useful additions for queues, API-first apps, logging, and mail transport support. It also includes a solid batch of targeted fixes in validation, Vite asset loading, pagination cursors, and request validation behavior.
What's new
-
Adds debounceable queued jobs so repeated dispatches of the same job within a time window collapse down to the last dispatch. You can opt in with a
#[DebounceFor]attribute on anyShouldQueuejob or apply debouncing at dispatch time; earlier queued copies are skipped when they reach execution, and missing cache entries fail open so jobs are not silently lost after cache eviction orcache:clear(#59507). -
Adds
prefersJsonResponses()to the application builder for API-first apps that getAccept: */*from clients likecurl, mobile SDKs, or generic HTTP libraries. Enabling it inbootstrap/app.phpprepends middleware that rewrites ambiguousAcceptheaders toapplication/json, while leaving requests that already express a specific media type unchanged and preserving the original header inX-Original-Accept(#59753). -
The built-in health route now returns JSON when the request expects JSON.
/upresponds with{"status":"Application is up"}on success or{"status":"Application experiencing problems"}when diagnostics fail outside debug mode, while keeping the existing HTML response for non-JSON requests and the same200/500status codes (#59710). -
Introduces
Illuminate\Log\Formatters\JsonFormatterfor structured JSON logs that include enriched exception context, including context from previous exceptions. To use it, set'formatter' => Illuminate\Log\Formatters\JsonFormatter::classinconfig/logging.phpinstead of Monolog’s JSON formatter (#59756). -
Adds first-party support for Cloudflare Email Service as a mail transport. It uses Symfony’s HTTP client, so you’ll need
composer require symfony/http-client, then configureaccount_idandtokenunder thecloudflareservice inconfig/services.php(#59735). -
SQS queue connections can now use named credential providers via the
credentialsconfig key, includingecsandinstance. This also improves Laravel Cloud managed queues by forcingecscredentials and overriding the SQS region fromLARAVEL_CLOUD_REGIONwhenLARAVEL_CLOUD_MANAGED_QUEUES=1is enabled (#59733). -
More manager APIs now accept enums for driver or connection names. This release adds enum support to
BroadcastManager,PasswordBrokerManager, andNotificationChannelManager, so enum-backed names can be passed directly to methods likeBroadcast::connection(),Password::broker(), and notification channel/driver resolution methods (#59713, #59714, #59783). -
Eloquent and testing ergonomics got a few small improvements. Child models can now use a
#[Table]attribute to override a parent model’s table definition,hasAttached()accepts an array of pivot attribute arrays for building many attached records more cleanly, andassertDatabaseHas()/assertDatabaseMissing()can now accept multiple record arrays in one call (#59701, #59723, #59752).
Fixes
-
Fixes number abbreviation rollover so values like
999500format as1Mor1 millioninstead of1,000Kor1,000 thousand(#59692). -
Fixes
Cursor::fromEncoded()so malformed but validly decoded payloads now returnnullinstead of triggering warnings and producing broken cursor instances (#59699). -
Fixes
FormRequest::failOnUnknownFields()so query string parameters likepage,perPage,expires, andsignatureare no longer treated as unknown payload fields (#59728). -
Fixes a
TypeErrorin thedigits_betweenvalidation rule when non-string, non-numeric values such as arrays are passed (#59717). -
Fixes Vite asset resolution so CSS from nested chunk imports is included instead of only CSS from direct imports of an entrypoint (#59662).
-
Fixes
Cache::flushLocks()when using thefailovercache driver by adding lock flushing support toFailoverStore(#59738). -
Fixes decryption key validation so MAC checks run across all configured keys rather than stopping based on key position in the rotation list (#59742).
-
Fixes
assertModelMissing()andassertModelExists()so they do not silently pass on empty results (#59772).
Other notable changes
-
The
jobs.attemptscolumn type was widened from tiny integer to small integer, allowing more than 255 attempts in database-backed queues (#59718). -
Queue::route()now treats a string mapping as a queue name only, rather than also applying it as the connection name (#59711). -
Validation for
decimal,max_digits, andmin_digitsnow explicitly casts numeric values to strings beforepreg_match()(#59739).
Contributors
@lucasmichot, @Button99, @jackbayliss, @bipinks, @paulandroshchuk, @matthewnessworthy, @WendellAdriel, @cyrodjohn, @sumaiazaman, @ju-gow, @karim1999, @kieranbrown, @ma32kc, @jnoordsij, @cosmastech, @dwightwatson, @yousefkadah