Laravel v13.6.0 introduces debounceable queued jobs — when the same job is dispatched multiple times within a time window, only the last dispatch executes. This release also adds JSON response support for the built-in health route, a new JsonFormatter for logging, Cloudflare Email Service integration, and several internal improvements.
- Debounceable queued jobs with
#[DebounceFor]attribute - JSON responses for the built-in health route (
/up) - New JsonFormatter for structured JSON logging
- Cloudflare Email Service support
- Array of pivot arrays support for
hasAttached - Improved model assertions in testing
- Various bug fixes and performance improvements
What's New
Debounceable Queued Jobs
This release adds debouncing support for queued jobs. When the same job is dispatched multiple times within a time window, only the last dispatch executes — earlier dispatches are silently discarded at execution time.
Apply the #[DebounceFor] attribute to any ShouldQueue job:
use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Queue\Attributes\DebounceFor; #[DebounceFor(30)]class RebuildSearchIndex implements ShouldQueue{ use Dispatchable, InteractsWithQueue, Queueable; public function __construct(public int $documentId) {} public function debounceId(): string { return (string) $this->documentId; } public function handle(): void { SearchIndex::rebuild($this->documentId); }} // User edits a document 10 times in 30 seconds — only the last dispatch runsRebuildSearchIndex::dispatch($document->id);
Debouncing can also be applied at the dispatch site without modifying the job class:
dispatch(new SyncExternalData($accountId))->debounceFor(30);
A maxWait parameter caps how long a job can be deferred:
#[DebounceFor(30, maxWait: 120)]class SyncDashboard implements ShouldQueue { ... }
This differs from ShouldBeUnique — with debounce, the last dispatch wins (at execution time), while ShouldBeUnique rejects additional dispatches at dispatch time.
Pull Request: #59507 by @matthewnessworthy
JSON Responses for Health Route
The framework's built-in health route (/up) now returns JSON when the request expects JSON. Previously, the route always rendered HTML, which was awkward for API-only applications whose load balancers and uptime monitors expect JSON.
When $request->expectsJson() is true, /up now returns:
{"status": "Application is up"}
Or when a DiagnosingHealth listener throws and debug mode is off:
{"status": "Application experiencing problems"}
Status codes (200 / 500) remain unchanged, and non-JSON requests continue receiving the existing Blade page.
Pull Request: #59710 by @WendellAdriel
JsonFormatter
A new JsonFormatter provides structured JSON logging output, useful for log aggregation systems like the ELK stack or Datadog:
use Monolog\Handler\StreamHandler;use Monolog\Logger;use Illuminate\Support\Facades\Log; $handler = new StreamHandler('php://stdout');$handler->setFormatter(new \Illuminate\Log\Formatters\JsonFormatter); Log::build(['handler' => $handler])->info('User logged in', ['user_id' => 1]);
Pull Request: #59756 by @cosmastech
Cloudflare Email Service Support
Laravel now supports Cloudflare Email Service for sending emails through Cloudflare's infrastructure. Configure the transport in config/services.php:
'cloudflare' => [ 'account_id' => env('CLOUDFLARE_ACCOUNT_ID'), 'token' => env('CLOUDFLARE_TOKEN'),],
Pull Request: #59735 by @dwightwatson
Array of Pivot Arrays for hasAttached
The factory hasAttached method now accepts an array of pivot arrays, making it easier to create models with different pivot values:
$user = User::factory() ->hasAttached(Role::factory()->count(2), [ ['admin' => 'Y'], ['admin' => 'N'], ]) ->create();
Pull Request: #59723 by @jackbayliss
Improved Model Assertions
Database model assertions in tests now accept arrays, allowing you to check multiple records in a single call:
$this->assertDatabaseHas(User::class, [ ['name' => 'Alice', 'email' => 'alice@example.com'], ['name' => 'Bob', 'email' => 'bob@example.com'],]); $this->assertDatabaseMissing(User::class, [ ['name' => 'Charlie', 'email' => 'charlie@example.com'],]);
Pull Request: #59752 by @jackbayliss
Other Fixes and Improvements
Queue:
- Ensure
Queue::routestring defaults to queue only (#59711 by @jackbayliss) - Support named credential providers for SQS queue connections (#59733 by @kieranbrown)
Validation:
- Fix
digits_betweenvalidation rule on non-string values (#59717 by @sumaiazaman) - Cast to string before preg_match in decimal, max_digits, and min_digits rules (#59739 by @sumaiazaman)
Enum Support:
- Add enum support to PasswordBrokerManager (#59714 by @sumaiazaman)
- Add enum support to BroadcastManager (#59713 by @sumaiazaman)
- Add enum support to NotificationChannelManager (#59783 by @yousefkadah)
Other:
- Return null from
Cursor::fromEncodedfor malformed payloads (#59699 by @bipinks) - Validate MAC across all decryption keys (#59742 by @ma32kc)
- Use generic TModel in additional places in Factory class (#59780 by @jnoordsij)
References