Route Metadata Support and More in Laravel 13.17
Laravel #Laravel #Laravel 13 #Routing #PostgreSQL #Queues

Route Metadata Support and More in Laravel 13.17

4 min read Mohamed Said Mohamed Said

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:cache support.
  • Postgres transaction pooler support lands with a single pooled => true config flag and automatic direct-endpoint routing for DDL commands.
  • The dev:list command 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

Found this useful?

Frequently Asked Questions

3 questions
Q01 How does route metadata cascading work in Laravel 13.17?
Metadata defined on a route group cascades to every route inside it. Associative arrays are merged recursively, so child routes can add or override individual keys without losing values set by the parent group. Scalar values and lists replace inherited ones rather than merging.
Q02 Do I need to change existing database connections to use the new Postgres pooler support?
No. The change is fully backward compatible. Only connections that explicitly set `pooled => true` in their database config switch to emulated prepares. All other connections continue to use native prepared statements as before.
Q03 What happens to remaining job attempts when a Should Not Retry exception is thrown?
When the `retry()` method on an exception returns `false`, Laravel marks the job as failed immediately without consuming any remaining retry attempts. This prevents unnecessary re-queuing for errors that are known to be unrecoverable.

Continue reading

More Articles

View all