News

RouteKey Model Attribute in Laravel 13.21

Published
RouteKey Model Attribute in Laravel 13.21 image

Release updates

Never miss a Laravel release

Get an email whenever a new Laravel release lands.

Laravel 13.21 adds a #[RouteKey] class attribute for customizing route model binding on Eloquent models, a base64 validation rule, a #[RequestAttribute] contextual attribute for injecting request attributes, and PNG, GIF, AVIF, and BMP output support in the Image component. The Laravel team tagged v13.21.0 and v13.21.1 on July 21, 2026; the patch tag only bumps the framework's version constant, so the two are covered together here.

  • #[RouteKey] attribute for Eloquent route model binding
  • New base64 validation rule
  • #[RequestAttribute] contextual attribute
  • PNG, GIF, AVIF, and BMP output formats for the Image component
  • Customizable application builder and an illuminate/concurrency subsplit

What's New

#[RouteKey] Attribute for Eloquent Models

Customizing the column used for route model binding has always meant overriding getRouteKeyName() on the model. Following the pattern set by #[ObservedBy] and #[ScopedBy], models can now declare the route key with a class attribute instead:

use Illuminate\Database\Eloquent\Attributes\RouteKey;
 
#[RouteKey('slug')]
class Post extends Model
{
// ...
}

With the attribute in place, implicit route model binding resolves Post by its slug column, and getRouteKeyName() falls back to the primary key when no attribute is present. Contributed by @nimnaherath in #60841.

base64 Validation Rule

A base64 rule joins the validator's string format checks, filling a gap that libraries like Zod already cover. The rule verifies that a value is a valid RFC 4648 Base64 string:

$request->validate([
'signature' => ['required', 'base64'],
]);

The check requires a canonical encoding: the value must decode in strict mode and re-encode to the exact same string, so padding mistakes and stray characters fail validation. Contributed by @lucasmichot in #60808.

#[RequestAttribute] Contextual Attribute

Middleware often stashes resolved objects on the request's attribute bag, a tenant or organization resolved from an API key, for example. Pulling those back out means calling $request->attributes->get() and type-hinting by hand. The new #[RequestAttribute] contextual attribute injects the value directly into a resolved parameter:

use Illuminate\Container\Attributes\RequestAttribute;
 
class InventoryController
{
public function index(#[RequestAttribute('org')] Organization $org)
{
return $this->inventoryService->getForOrg($org);
}
}

Contributed by @cosmastech in #60847.

More Output Formats for the Image Component

The Image component introduced in Laravel 13.20 could only convert to WebP, JPG, and JPEG through its fluent methods, even though the bundled Intervention Image encoders support more. This release adds toPng(), toGif(), toAvif(), and toBmp():

use Illuminate\Support\Facades\Image;
 
Image::fromUpload($request->file('avatar'))
->cover(400, 400)
->toAvif()
->quality(80)
->store('avatars');

The change also fixes Image::extension(), which was missing the image/avif MIME mapping and would have produced a .bin extension for stored AVIF output. Contributed by @Tresor-Kasenda in #60713.

Customizable Application Builder

Application::configure() previously hardcoded the ApplicationBuilder class, so packages extending Laravel's Application had to override the whole method to swap it out. A protected static $applicationBuilder property now lets subclasses provide their own builder class while keeping the existing API. See #60848.

Concurrency Subsplit

The Illuminate\Concurrency component now has its own read-only subsplit, joining the other Illuminate components published as standalone packages. See #60836.

Other Fixes and Improvements

  • Database transaction rollback callbacks now fire correctly (#60777), and a new lost connection message is detected for automatic reconnects (#60819)
  • Question marks are escaped in Grammar::whereColumn() (#60832)
  • InvalidPayloadException messages now include the job name and queue (#60799)
  • Passing an enum to LogManager::forgetChannel() no longer throws a TypeError (#60801), and RedisTaggedCache::decrement() handles enum keys (#60821)
  • Str::wordWrap() handles multibyte strings correctly (#60814)
  • Contextual attribute caching no longer collides across properties of the same class (#60815), and falsey concurrency exception parameters are preserved (#60822)
  • Fixed host port parsing in the serve command (#60828) and an undefined index in Pipeline\Hub::pipe() (#60802)

References

Paul Redmond photo

Staff writer at Laravel News. Full stack web developer and author.

Sponsored

laravelcloud logo
Laravel Cloud

Easily create and manage your servers and deploy your Laravel applications in seconds.

Visit Laravel Cloud

The latest

View all →
Laravel monitoring that doesn't bill you by your traffic image

Laravel monitoring that doesn't bill you by your traffic

Read article
Mock PHP Classes in Tests With the Double Library image

Mock PHP Classes in Tests With the Double Library

Read article
Laravel Discount: Coupon Codes, Usage Limits, and Stacking image

Laravel Discount: Coupon Codes, Usage Limits, and Stacking

Read article
Laravel Truss: Live Interactive Database ER Diagrams image

Laravel Truss: Live Interactive Database ER Diagrams

Read article
Laravel artisan dev: Run Server, Queue, Logs, and Vite image

Laravel artisan dev: Run Server, Queue, Logs, and Vite

Read article
Validate and Convert HEIC Images in Laravel image

Validate and Convert HEIC Images in Laravel

Read article