Changelog

New updates and improvements to Laravel's open source products.

April 2026

Laravel Framework 13.x

Add Debounceable Queued Jobs

Pull request by @matthewnessworthy

Bursty workloads finally have a clean answer. Debounceable jobs keep only the last dispatch in a window, so a user editing the same document ten times in thirty seconds triggers a single rebuild instead of ten. Apply the #[DebounceFor] attribute to any queued job, or debounce at the call site without touching the class:

1use Illuminate\Contracts\Queue\ShouldQueue;
2use Illuminate\Queue\Attributes\DebounceFor;
3 
4#[DebounceFor(30)]
5class RebuildSearchIndex implements ShouldQueue
6{
7 public function __construct(public int $documentId) {}
8 
9 public function debounceId(): string
10 {
11 return (string) $this->documentId;
12 }
13 
14 public function handle(): void
15 {
16 SearchIndex::rebuild($this->documentId);
17 }
18}

Where ShouldBeUnique keeps the first dispatch and rejects the rest, debouncing flips that around so the most recent dispatch always wins. A JobDebounced event fires for any superseded job if you want to track it. Read more in the queue documentation.

Support JSON Responses for the Built-in Health Route

Pull request by @WendellAdriel

API-only apps can stop scraping HTML from /up. The built-in health route now returns JSON when the request asks for it, which makes load balancers, uptime monitors, and orchestrators a lot happier:

1{ "status": "Application is up" }

Status codes stay the same, and browser requests still get the existing Blade page. No config required.

Introduce JsonFormatter

Pull request by @cosmastech

Exception context is one of those things you only realize you needed after staring at production logs for hours. The new Illuminate\Log\Formatters\JsonFormatter ensures context() data on your custom exceptions actually shows up in structured logs, including context from previous exceptions in a chain. Wire it up in config/logging.php:

1'formatter' => Illuminate\Log\Formatters\JsonFormatter::class,

Now an exception like this carries its enriched context all the way through to the log entry:

1class MyException extends \RuntimeException
2{
3 public function context(): array
4 {
5 return [
6 'luke' => 'cosmastech',
7 'taylor' => 'taylorotwell',
8 ];
9 }
10}

Whether the exception is sent through report() or written via Log::error() with an exception key, the structured payload now includes everything you put on the exception itself.

Add prefersJsonResponses() to the Application Builder

Pull request by @WendellAdriel

Building an API and tired of curl requests coming back as HTML? One line in bootstrap/app.php now treats broad Accept headers as JSON, so auth redirects, validation errors, and exception pages all serialize properly for clients that didn't ask for HTML:

1return Application::configure(basePath: dirname(__DIR__))
2 ->withRouting(
3 web: __DIR__.'/../routes/web.php',
4 commands: __DIR__.'/../routes/console.php',
5 )
6 ->prefersJsonResponses()
7 ->create();

Clients that explicitly request text/html are left alone, and the original Accept value is preserved on X-Original-Accept if you need it for logging. Default behavior is unchanged unless you opt in.

Add Support for Cloudflare Email Service

Pull request by @dwightwatson

Cloudflare's Email Service joins the list of first-class mailers in Laravel. Drop your credentials into config/services.php:

1'cloudflare' => [
2 'account_id' => env('CLOUDFLARE_ACCOUNT_ID'),
3 'token' => env('CLOUDFLARE_TOKEN'),
4],

Then point your mailer at it and send like usual. Same Symfony HTTP Client setup the existing transports use, so there's nothing new to learn.

Add First-Class Redis Cluster Support for Queue and ConcurrencyLimiter

Pull request by @timmylindh

If you've ever fought a CROSSSLOT error on AWS ElastiCache Serverless or any Redis Cluster setup, this one is for you. Laravel's Redis queue and ConcurrencyLimiter now wrap queue names in hash tags automatically when they detect a cluster connection, so all related keys land on the same slot:

1queues:{default} -> slot for "default"
2queues:{default}:delayed -> slot for "default"
3queues:{default}:reserved -> slot for "default"
4queues:{default}:notify -> slot for "default"

Different queues still distribute across the cluster, the same pattern Sidekiq and BullMQ use. The PhpRedis cluster connector also picks up ACL auth and retry/backoff parity with standalone connections, which matters during ElastiCache scaling events. Standalone users see zero change. The full breakdown is in the queue documentation.

Add Queue Methods to Inspect Jobs

Pull request by @jackbayliss

Three new methods on the Queue facade let you peek at what is actually sitting on your queues without reaching for DB::table() and decoding payloads by hand:

1Queue::pendingJobs();
2Queue::delayedJobs();
3Queue::reservedJobs();

Each returns a collection of InspectedJob instances exposing the uuid, job name, attempts, and creation time. That opens up some genuinely useful patterns:

1Queue::reservedJobs('high-priority-queue')->first()->name;
2// => 'App\Jobs\SendEmail'
3 
4Queue::pendingJobs()->countBy('name');
5// => ['App\Jobs\SendEmail' => 1842, 'App\Jobs\ProcessOrder' => 43]

Perfect for deployment scripts that need to wait for specific jobs to finish, dashboards, and ad-hoc debugging. Works with the Redis and Database drivers; other drivers return an empty collection.

Form Request Strict Mode

Pull request by @NurullahDemirel

Strict mode lands in form requests, mirroring the spirit of Model::shouldBeStrict(). Flip it on in your AppServiceProvider and any incoming field that isn't declared in rules() will fail validation instead of silently slipping through:

1use Illuminate\Foundation\Http\FormRequest;
2 
3public function boot(): void
4{
5 FormRequest::failOnUnknownFields(! app()->isProduction());
6}

Need to opt a single request out (say, a public webhook with unpredictable payloads)? Set the property on the class:

1class PublicWebhookRequest extends FormRequest
2{
3 protected ?bool $failOnUnknownFields = false;
4 
5 public function rules(): array { /* ... */ }
6}

It's fully backward compatible, off by default, and a great safety net during development. Learn more in the validation documentation.

Inertia

Add onHttpException, onNetworkError, And Response to onSuccess in useHttp

Pull request by @pascalbaljet

The useHttp hook gets the same error callbacks Inertia visits already have. No more wrapping calls in try/catch just to handle a 500 or a dropped connection. There's also a second argument on onSuccess that hands you the raw HttpResponse, so telling a 200 apart from a 204 is now trivial. Available across the React, Vue, and Svelte adapters.

Agent Skills

Add Laravel Nightwatch Plugin

Pull request by @pushpak1300

Configuring Laravel Nightwatch is now a built-in skill for both Claude Code and Cursor. Install the plugin from the marketplace and your agent has the steps it needs to wire Nightwatch into your project, no copy-pasting setup instructions from the docs.

Boost

Add Laravel Cloud Integration to Install Command

Pull request by @pushpak1300

The Boost installer now offers Laravel Cloud as one of the integrations you can pull in, which means the deploying-laravel-cloud skill ships alongside your other agent tooling. One less manual step on the way to your first deploy. Read more about getting started at Laravel Cloud.

Skills List Command

Pull request by @me-shaon

Wondering what skills are actually available in your project? A new Artisan command shows you:

1php artisan boost:skill-list

You get a clean table of skill names alongside their source (the package they came from, or local if it's yours), with custom skills called out so they're easy to spot. Pass --json for machine-readable output if you're scripting around it:

1[
2 {
3 "name": "livewire-development",
4 "description": "Build dynamic interfaces using Livewire",
5 "package": "livewire/livewire",
6 "custom": false
7 },
8 {
9 "name": "my-custom-skill",
10 "description": "A custom skill for my project",
11 "package": "user",
12 "custom": true
13 }
14]

Add Kiro IDE Agent Support

Pull request by @oniice

Kiro, Amazon's AI-powered IDE, is now a first-class agent target alongside Cursor, Claude Code, and Copilot. Boost detects Kiro automatically and writes guidelines, skills, and MCP config to the right places (.kiro/steering/boost.md, .kiro/skills/, and .kiro/settings/mcp.json). Whatever editor you live in, your Laravel context comes with you.

Dusk

Add clickOnceEnabled() and clickOnceVisible()

Pull request by @weshooper

Two small additions, big quality-of-life win. The new clickOnceEnabled() and clickOnceVisible() browser methods wait for an element to be ready before clicking it exactly once, no pause() calls, no flaky retries:

1$browser->clickOnceVisible('@save-button');
2$browser->clickOnceEnabled('@submit-button');

A clean way to keep your test suite stable on slower pages.

Echo

Svelte 5 Adapter

Pull request by @joetannenbaum

Svelte 5 developers can now use Laravel Echo with the same ergonomics React and Vue have enjoyed. The new useEcho rune lets you subscribe to channels and react to events with full reactivity:

1<script>
2 import { useEcho } from '@laravel/echo-svelte';
3 
4 const { channel } = useEcho('orders', 'OrderShipped', (e) => {
5 console.log(e.order);
6 });
7</script>

Real-time features in Svelte are now a single import away.

Horizon

Add First-Class Redis Cluster Support

Pull request by @timmylindh

A companion to the framework's queue cluster work, Horizon now runs cleanly on AWS ElastiCache Serverless and other Redis Cluster deployments. The Horizon prefix is automatically wrapped in a hash tag so all keys land on the same slot, and Horizon::use() registers cluster connections properly instead of extracting a single node. Standalone setups behave exactly as before, so no migration is needed if you're not on a cluster. Full setup guide in the Horizon documentation.

Laravel Installer

Concise Output With Prompt's Task Function

Pull request by @joetannenbaum

laravel new is a much calmer experience now. Instead of a wall of composer, npm, and artisan output, each phase (project create, key generate, migrations, frontend install, Pest, Boost, git init, GitHub push) renders as its own task with clear pass or fail indicators thanks to Laravel Prompts' task() helper. Want the full firehose? Pass -v and the original streaming output is right there.

Starter Kits

Adds PAO by Default

Pull request by @nunomaduro

PAO ships out of the box with every starter kit (Inertia, Livewire, blank, WorkOS variants and all). New apps come ready for AI-friendly tooling output with no extra setup.

Add Toast Notifications

Pull request by @WendellAdriel

Generic "Saved" messages are out, proper toast notifications are in. All 21 starter kit variants now use specific, translatable messages like "Profile updated." or "Team created." Livewire kits use Flux's native Flux::toast, while Inertia kits use Sonner with a tidy Inertia::flash pattern that's identical across React, Svelte, and Vue. Polished feedback, consistent everywhere.

MCP

Add MCP UI App Support

Pull request by @pushpak1300

MCP tools were text-only until now. With MCP UI App support, a tool can render a self-contained HTML app inside a sandboxed iframe in the host. Scaffold one with a single command:

1php artisan make:mcp-app-resource DashboardApp

The default handle() auto-infers the Blade view from the class name, so the PHP side stays minimal:

1class DashboardApp extends AppResource
2{
3 public function handle(Request $request): Response
4 {
5 return Response::view('mcp.dashboard-app', [
6 'title' => $this->title(),
7 ]);
8 }
9}

The view is the entire app, HTML, JS, and CSS in one file with the bundled SDK already inlined:

1<x-mcp::app title="Dashboard">
2 <x-slot:head>
3 <script type="module">
4 createMcpApp(async (app) => {
5 const result = await app.callTool('get-data');
6 document.getElementById('output').textContent = result.content[0]?.text;
7 });
8 </script>
9 </x-slot>
10 <div id="output"></div>
11</x-mcp::app>

Link a tool to the app with the #[RendersApp] attribute, optionally hiding helper tools from the model so only the UI can call them. No npm, no Vite, just Blade.

Passkeys

Laravel now ships a full passkey story instead of asking you to assemble WebAuthn by hand.

Server Side

laravel/passkeys-server is published on Packagist as laravel/passkeys. It brings migrations, routes for login, confirmation, and credential management, plus WebAuthn actions, events, and escape hatches when you need custom authorization, responses, or your own route definitions.

Client Side

@laravel/passkeys (source) handles browser ceremonies—registration and verification—with a small core API and first-class helpers for React, Vue, and Svelte, including SSR-safe hooks so client-only APIs do not fight your framework.

Fortify

Laravel Fortify integrates the stack behind Features::passkeys() and a passkeys section in config/fortify.php, so Fortify apps get the same endpoints and contracts (PasskeyUser, PasskeyAuthenticatable) without reimplementing glue.

Together: server package, npm client, and Fortify line up on routes and contracts so passwordless auth stays boring to wire up and portable across stacks.

Pint

Ensures Agent Output Is Consistent With PAO

Pull request by @nunomaduro

When agents run Pint alongside other tooling, consistent output matters. Pint's agent reporter now mirrors the PAO format, adding a tool key and using passed instead of pass:

1{"tool":"pint","result":"passed"}
2{"tool":"phpstan","result":"passed","errors":0}
3{"tool":"pest","result":"passed","tests":52,"passed":52,"assertions":90,"duration_ms":534}

Small change, much easier to parse in agent workflows.

VS Code Extension

Support for New Laravel 13 Attributes

Pull request by @N1ebieski

The VS Code extension now understands Laravel 13's new attributes. You get autocompletion, hover tooltips, navigation, and diagnostics for routing attributes like Authorize, Middleware, and RedirectToRoute, plus model attributes like Fillable, Guarded, Hidden, Visible, and Appends. Writing controllers and Eloquent models with attributes feels just as smooth as the array syntax did.

Add Common Artisan Commands With Terminal Execution Support

Pull request by @TitasGailius

Thirty common Artisan commands are now a keystroke away in the VS Code command palette, including migrate, migrate:fresh, tinker, db, route:list, pail, queue:retry, schedule:list, cache:clear, and more. Each runs in a dedicated Laravel Artisan terminal so you can read the output directly. Less context switching, more shipping.

PestPHP Intellisense

Pull request by @TitasGailius

Pest test files get a real intellisense upgrade. The extension now reads your Pest config to generate helper docblocks that preserve the right $this type inside hooks and tests, surface pest()->extend(...) and pest()->use(...) setups for autocomplete and navigation, and expose any custom expectations you have defined. Generated docblocks live in storage/framework/testing/_pest.php, which is gitignored. Writing Pest tests in VS Code feels noticeably better.

Add Go to Route Command

Pull request by @TitasGailius

A new Laravel: Go to route command opens a fuzzy picker of every registered route, by path or name, and jumps straight to the handler. No more grepping for a controller method or scanning route:list. One of those small commands you wonder how you lived without after a week.