Laravel Open Source Changelog (December 2025)
New updates and improvements to Laravel's open source products.
Laravel Framework 12.x
[12.x] Add Ability to Run Callbacks After Building an HTTP Response
Pull request by @cosmastech
A new afterResponse method was added to the HTTP Client, which allows the user to inspect and mutate the response returned from an HTTP call:
Http::acceptJson()
->withHeader('X-Shopify-Access-Token', $credentials->token)
->baseUrl("https://{$credentials->shop_domain}.myshopify.com/admin/api/2025-10/")
->afterResponse(
// Report any deprecation notices that were in the header
function (Response $response) use ($credentials) {
if ($header = $response->header('X-Shopify-API-Deprecated-Reason')) {
event(new ShopifyDeprecationNotice($credentials->shop, $header));
}
})
->afterResponse(
// Map the response into our own custom response class
fn (Response $response) => new ShopifyResponse($response->toPsrResponse()),
)
->afterResponse(
// Report the cost of the query
static fn (ShopifyResponse $response) => QueryCostResponse::report(
$response->getQueryCost(),
$credentials->shop
),
);[12.x] Introduce FluentPromise to Allow for Cleaner Chaining in Pool
Pull request by @cosmastech
Userland chaining in Http::pool is now possible with the introduction of FluentPromise. Previously, the chain would return the original response, limiting flexibility. With this change, users can access the underlying array and return whatever they wish:
$response = Http::pool(function (Pool $pool) {
$pool->as('cosmatech')
->get('https://cosmastech.com')
->then(
fn ($response) => strlen($response->body())
);
$pool->as('laravel')
->get('https://laravel.com')
->then(
fn ($response) => strlen($response->body())
);
});
/*
array:2 [
"cosmatech" => 9095
"laravel" => 1422023
]
*/Introduce lazy Object and proxy Object Support Helpers
Pull request by @timacdonald
Two new helpers, lazy and proxy, were added to make PHP's new lazy objects more ergonomic to use.
<?php
use Illuminate\Support\Facades\Http;
use Vendor\Facades\ResultFactory;
use Vendor\Result;
use function Illuminate\Support\lazy;
use function Illuminate\Support\proxy;
$response = Http::get(...);
$instance = lazy(Result::class, fn () => [$response->json()]);
$instance = proxy(Result::class, fn (): Result => ResultFactory::make($response->json()));[12.x] Add Reload Command and Allow Services to Register
Pull request by @barryvdh
A new php artisan reload command was introduced, allowing service providers to add their own commands for reloading. This makes it easier for services to specify one command to include in their deployment steps after the deployment is completed.
The applicable reload commands have already been added to Laravel Horizon, Pulse, Reverb, and Octane.
public function boot()
{
$this->reloads('reverb:restart');
}Modernize Email Template
Pull request by @taylorotwell
The default Laravel email template was cleaned up and modernized, giving it a fresh coat of paint and an elevated, professional appearance.
Wayfinder
The next version of Wayfinder entered public beta.
This version generates far more TypeScript from your Laravel app than the previous version, including routes and controller actions, named routes, form requests, Eloquent models, PHP enums, Inertia.js page props, Inertia shared data, broadcast channels, broadcast events, environment variables, and more.
Two new packages used by Wayfinder were also introduced into public beta:
Surveyor
Laravel Surveyor is a powerful (mostly) static analysis tool designed to extract detailed PHP and Laravel-specific information from your code. It parses and analyzes PHP files to extract comprehensive metadata about classes, methods, properties, return types, and more, making this information available in a structured, consumable format for use by other tools and packages.
use Laravel\Surveyor\Analyzer\Analyzer;
$analyzer = app(Analyzer::class);
// Analyze a file by path
$result = $analyzer->analyze('/path/to/your/File.php');
// Access the analyzed scope
$scope = $result->analyzed();
// Access the class result
$classResult = $result->result();Ranger
Laravel Ranger is a supercharged introspection library for Laravel applications. It walks through your codebase and collects detailed information about your application's components, including routes, models, enums, broadcast events, environment variables, and Inertia.js components.
It uses Surveyor under the hood and extracts the results into detailed data transport objects for straightforward consumption.
use Laravel\Ranger\Ranger;
use Laravel\Ranger\Components;
use Illuminate\Support\Collection;
$ranger = app(Ranger::class);
// Register callbacks for individual items
$ranger->onRoute(function (Components\Route $route) {
echo $route->uri();
});
$ranger->onModel(function (Components\Model $model) {
foreach ($model->getAttributes() as $name => $type) {
//
}
});
$ranger->onEnum(function (Components\Enum $enum) {
//
});
$ranger->onBroadcastEvent(function (Components\BroadcastEvent $event) {
//
});
// Or register callbacks for entire collections
$ranger->onRoutes(function (Collection $routes) {
// Called once all of the routes have been discovered and processed
});
$ranger->onModels(function (Collection $models) {
// Called once all of the models have been discovered and processed
});
// Walk through the application and trigger all callbacks
$ranger->walk();Inertia
Support for Flash Data
Pull request by @pascalbaljet
Unlike regular props, Flash Data isn't persisted in the browser's history state, making it ideal for one-time notifications like toasts. On the frontend, Flash Data is available on page.flash. You can also listen for Flash Data using the global flash event or the onFlash callback.
<template>
<div v-if="page.flash.toast" class="toast">
{{ page.flash.toast.message }}
</div>
</template>router.on("flash", (event) => {
if (event.detail.flash.toast) {
showToast(event.detail.flash.toast);
}
});
router.post("/users", data, {
onFlash: ({ newUserId }) => {
// ...
},
});First-Party Support for Precognition
Pull requests by @pascalbaljet: #2684, #2700
Laravel Precognition is now baked directly into the useForm hook and the Form component; there is no need to install additional libraries. Live validation has never been easier.
<template>
<Form action="/users" method="post" #default="{ errors, invalid, validate, validating }">
<div>
<input name="name" @change="validate('name')" />
<p v-if="invalid('name')">{{ errors.name }}</p>
</div>
<div>
<input name="email" @change="validate('email')" />
<p v-if="invalid('email')">{{ errors.email }}</p>
</div>
<p v-if="validating">Validating...</p>
</Form>
</template>Optimize Page Data Size and Parsing
Pull request by @bram-pkg
Opt-in support was added for loading the initial Inertia page data from a <script type="application/json"> element instead of the body tag. This results in a greatly reduced initial page data size, faster parsing, and makes the initial page data a breeze to inspect with your browser's dev tools.
You can opt in to this behavior as follows:
createInertiaApp({
// ...
defaults: {
future: {
useScriptElementForInitialPage: true,
},
},
});Support for once() Props
Pull request by @pascalbaljet
Some data rarely changes, is expensive to compute, or is simply large. Rather than including this data in every response, once props are remembered by the client and reused on subsequent pages that include the same prop.
return Inertia::render('Billing', [
'plans' => Inertia::once(fn () => Plan::all()),
]);Boost
Add Resource and Prompts for Package Guidelines
Pull request by @pushpak1300
Previously, all third-party package guidelines needed to be added to the global context, which could grow unbounded as more packages were integrated.
Boost is now reducing global context bloat by adding guidelines for only actively used packages that are loaded, thereby improving token efficiency and leaving room for more application-specific information.
Echo
Event Payload Type Inference
Pull request by @joetannenbaum
Event payloads are now automatically inferred from the broadcast event if the user provides a module override file, resulting in a cleaner useEcho experience and less type management for the user.
import { App } from "./types";
declare module "@laravel/echo-react" {
interface Events {
".App.Events.UserCreated": {
user: App.Models.User;
};
".App.Events.OrderShipped": {
order: App.Models.Order;
user: App.Models.User;
};
}
}MCP
Add Completion Support
Pull request by @pushpak1300
Support was added for the MCP completion utility, allowing servers to provide IDE-like autocompletion suggestions for prompt arguments and resource template variables.
Add Annotation Support on Resources
Pull request by @pushpak1300
Three annotation types are now available for use with Resource classes: audience, priority, and lastModified. This adheres to the MCP specs and allows the server to provide hints to clients about how to use or display the resource.
Add structuredContent and outputSchema Support
Pull request by @macbookandrew
Support for output schemas and structured content was added to the MCP package, enabling better integration with ChatGPT Apps and AI clients that need parseable tool results.
VS Code Extension
Add Scope Parameters to the Repository and Docblock Generator
Pull request by @N1ebieski
Model scope parameters now appear in model helper docblocks, making it clear to the user which parameters are required by the query scopes they are using.
Add a Command That Generates Namespace
Pull request by @N1ebieski
A new "Generate Namespace" command was added to the extension, allowing the user to quickly generate the correct namespace for a class.