Laravel Open Source Changelog (September 2026)
New updates and improvements to Laravel's open source products.
Laravel Framework 13.x
Semantic and Hybrid Search for Typesense
Pull request by @tharropoulos
Scout's Typesense engine now supports semantic() and hybrid() searches. Model embedding settings can use Laravel AI to generate vectors from toSearchableEmbedding() or use Typesense's native auto-embedding; precomputed vectors are also supported. Applications can search by meaning alone or combine semantic matches with text results through the Scout builder.
Reliable MariaDB Vector Queries and an Eloquent Vector Cast
Pull request by @eas4ai
MariaDB vector distance queries now convert bound vectors with vec_fromtext(), fixing SQL errors when using methods such as whereVectorSimilarTo() and orderByVectorDistance(). The new AsVector Eloquent cast reads MariaDB's binary vectors or PostgreSQL-compatible text vectors as arrays of floats and accepts arrays or Arrayable values when writing them.
use Illuminate\Database\Eloquent\Casts\AsVector;
use Illuminate\Database\Eloquent\Model;
class Document extends Model
{
protected $casts = [
'embedding' => AsVector::class,
];
}Copy or Move Files Between Disks
Pull request by @jackbayliss
Filesystem disks now expose copyToDisk() and moveToDisk() for transferring files to another configured disk, optionally under a new path. Both methods stream the file and close the stream; moveToDisk() deletes the source only after the copy succeeds.
use Illuminate\Support\Facades\Storage;
Storage::disk('local')->copyToDisk('s3', 'reports/report.csv', 'archive/report.csv');
Storage::disk('local')->moveToDisk('backup', 'reports/report.csv');Choose Which Commands Run During Development
Pull request by @jackbayliss
Applications can now exclude vendor-provided or framework-default development commands from php artisan dev with DevCommands::withoutVendorCommands() and DevCommands::withoutDefaultCommands(). This lets projects keep their own development commands without maintaining a list of every vendor and default command name.
Mercure Broadcasting in Laravel Echo
Pull request by @dunglas
Laravel Echo now includes a Mercure connector built on the browser's native EventSource API, without a separate client library. It supports private, presence, and encrypted channels, along with whispers. The hub URL defaults to /.well-known/mercure on the current origin, and the React, Vue, and Svelte integrations can configure it with VITE_MERCURE_HUB_URL.
Chunk Collections by Adjacent Values
Pull request by @JosephSilber
The new chunkBy() method splits collections and lazy collections whenever a chosen value changes. Unlike groupBy(), it groups only consecutive matches: values with the same key that appear later form a separate chunk. Pass a property name or callback to choose the value to compare.
collect([1, 1, 2, 2, 1])->chunkBy(fn ($value) => $value);
// [[1, 1], [2, 2], [1]]One-Time Mail and Notification Assertions
Pull request by @talaridisTh
The mail and notification fakes now offer assertions for events that should happen exactly once: Mail::assertSentOnce(), Mail::assertQueuedOnce(), Notification::assertSentToOnce(), and Notification::assertSentOnDemandOnce(). These are shorter alternatives to the corresponding ...Times(..., 1) assertions.
Store SQL NULL with Collection and Array Object Casts
Pull request by @zeinrahmad76
AsCollection::nullable() and AsArrayObject::nullable() now opt in to storing a native SQL NULL when an attribute is set to null, so queries such as whereNull() can match it. Existing casts keep their previous behavior of storing the JSON "null" value unless the nullable variant is selected.
use Illuminate\Database\Eloquent\Casts\AsCollection;
use Illuminate\Database\Eloquent\Model;
class Order extends Model
{
protected $casts = [
'items' => AsCollection::nullable(),
];
}Request In-Place MySQL Index Changes
Pull request by @SanderMuller
MySQL schema migrations can now chain inplace() onto index and foreign key definitions to request ALGORITHM=INPLACE. Combined with the existing lock('none') option, this lets a migration explicitly request a less disruptive DDL operation instead of silently accepting a different algorithm; MySQL can reject operations it cannot perform under those constraints.
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('video_sessions', function (Blueprint $table) {
$table->index('video_id')->inplace()->lock('none');
});Count Worker Crashes Toward a Job's Exception Limit
Pull request by @williamjulianvicary
Jobs can opt in to counting an unexpectedly terminated worker attempt toward maxExceptions using the #[CountCrashesAsExceptions] attribute or $countCrashesAsExceptions property. This helps prevent jobs from retrying indefinitely after crashes or external worker kills; normal completions and worker-managed timeouts do not count as crashes. The feature uses a cache marker for opted-in jobs.
AI
Build AI Providers from Runtime Configuration
Pull request by @pushpak1300
Ai::build() creates a provider from a configuration array without changing the application's configured providers. This supports credentials loaded at runtime, such as tenant-specific keys, and allows built providers in failover lists. For queued agents, build the provider in the agent's provider() method so it can be recreated by the worker rather than building it only at the call site.
use Laravel\Ai\Ai;
$agent->prompt($text, provider: [
Ai::build(['driver' => 'anthropic', 'key' => $tenant->ai_key]),
]);Horizon
Logarithmic Queue Auto-Scaling in Horizon
Pull request by @Gummibeer
Horizon supervisors can now use the log auto-scaling strategy alongside time and size. It weights queue backlogs logarithmically, reducing the chance that one much larger queue takes nearly all available workers. This is useful when keeping smaller queues moving matters more than maximizing throughput on the largest backlog.
Scout
Use Meilisearch's Native Embedders with Scout
Pull request by @Strift
Scout's Meilisearch engine can now use Meilisearch's own embedders for semantic() and hybrid() queries by setting the model's embedding driver to meilisearch and supplying an embedder. Meilisearch then generates document and query embeddings, while a vector passed through options(['vector' => ...]) can override query embedding. The default laravel-ai driver remains unchanged.