Laravel 13.17: Route Metadata, Postgres Pooler, and More
The Laravel team released v13.17.0 on June 24, 2026, bringing several developer-quality-of-life improvements. The headline feature is first-class route metadata support, but the release also includes Postgres transaction pooler integration, a new dev:list Artisan command, and a cleaner way to prevent queue job retries at the exception level.
First-Class Route Metadata
Previously, attaching custom data to a route meant stuffing it into the action array with no guaranteed structure or serialization support. Laravel 13.17 promotes metadata to a proper route attribute that survives route:cache serialization and cascades through route groups.
Attaching and Reading Metadata
Route::get('/users', [UserController::class, 'index'])
->metadata(['head' => ['title' => 'Users']]);
// Read with dot notation and an optional default
$request->route()->getMetadata('head.title'); // 'Users'
$request->route()->getMetadata('head.author', 'Taylor');
Group Cascading
Metadata set on a group cascades to every child route. Associative arrays merge recursively; scalar values and lists replace inherited ones.
Route::metadata(['head' => ['robots' => ['noindex'], 'author' => 'Taylor']])
->group(function () {
Route::get('/users', [UserController::class, 'index'])
->metadata(['head' => ['title' => 'Users']]);
});
// getMetadata('head') =>
// ['robots' => ['noindex'], 'author' => 'Taylor', 'title' => 'Users']
Resource and singleton routes are supported. Use setMetadata() on a route instance to replace rather than merge.
Postgres Transaction Pooler Support
Transaction-mode poolers like PgBouncer, AWS RDS Proxy, and Neon are incompatible with native prepared statements. Laravel now handles this automatically when you set pooled => true in your database config.
'pgsql' => [
'driver' => 'pgsql',
'pooled' => true,
'url' => env('DATABASE_URL'),
// Optional direct endpoint for migrations and DDL
'direct' => env('DATABASE_DIRECT_URL'),
],
With pooled enabled, the driver switches to emulated prepares. Commands that require a persistent connection—migrate, schema:dump, db:wipe—automatically route to the direct endpoint. Connections without pooled => true keep existing behavior, making the change fully backward compatible.
New dev:list Artisan Command
Building on the artisan dev command added in 13.16.0, dev:list shows every registered dev process and its source (your application or a vendor package).
php artisan dev:list
php artisan dev:list --except-vendor
php artisan dev:list --only-vendor
php artisan dev:list --filter=reverb
php artisan dev:list --json
Should Not Retry Exception Handler for Queued Jobs
Queued jobs can now decide at the exception level whether a failure should trigger a retry. Add a retry() method directly to the exception class:
class PaymentGatewayException extends RuntimeException
{
public function retry(): bool
{
return false;
}
}
For exceptions you do not own, register the behavior in your application bootstrap:
->withExceptions(function (Exceptions $exceptions) {
$exceptions->retry(PaymentGatewayException::class, fn () => false);
})
When retry() returns false, the job is marked as failed immediately without consuming remaining attempts.
Other Notable Changes
between()/unlessBetween()timezone fix — the timezone is now evaluated when the filter runs, not when the chain is defined, so call order no longer matters.schema:dump --without-migration-data— omits migration table rows from the dump, useful for clean test setup.- Reduced cache reads when debouncing jobs with
maxWait(two reads per dispatch down to one). - Improved typehints across
InteractsWithData, boolean/numeric validation, and array shapes.
Key Takeaways
- Route metadata is now a first-class attribute with dot-notation access, group cascading, and
route:cachesupport. - Postgres transaction pooler support lands with a single
pooled => trueconfig flag and automatic direct-endpoint routing for DDL commands. - The
dev:listcommand makes it easy to audit all registered dev processes and their origin. - Queue jobs can now short-circuit retries at the exception class level, reducing unnecessary attempts and queue pressure.
- The
between()/unlessBetween()timezone bug is fixed; call order in the scheduler chain no longer matters.
Source: Laravel News — Route Metadata Support in Laravel 13.17