Laravel 13.22 adds a #[BindWhen] attribute for conditional container bindings, a Validator::fakeDnsLookups() method for testing DNS-backed validation rules, #[Delay] attribute support for batched and bulk-dispatched jobs, and comma-separated queue names in the queue:clear command. The Laravel team released v13.22.0 on July 24, 2026.
#[BindWhen]attribute for conditional container bindings- Fake DNS lookups in the
active_urlandemail:dnsvalidation rules #[Delay]attribute support forBus::batch()andQueue::bulk()- Multi-queue support in
queue:clear - A macroable rate limiter, restored HTTP fake stream bodies, and assorted fixes
What's New
#[BindWhen] Attribute for Conditional Bindings
The #[Bind] attribute ties an interface to a concrete implementation, but its only conditional hook is the environments argument. The new #[BindWhen] attribute accepts a closure that receives the container, so a binding can depend on configuration, feature flags, or anything else resolvable at runtime:
use Illuminate\Container\Attributes\Bind;use Illuminate\Container\Attributes\BindWhen; #[BindWhen(BetaPaymentGateway::class, static function ($container) { return $container->make('config')->get('features.payments.beta');})]#[Bind(FakePaymentGateway::class, environments: ['local', 'testing'])]#[Bind(StripePaymentGateway::class)]interface PaymentGatewayInterface {}
The attribute is repeatable and conditions are evaluated in declaration order, so conditional bindings can sit ahead of a default #[Bind] fallback. Note that closures in attribute arguments are a PHP 8.5 language feature. Contributed by @ziadoz in #60862.
Faking DNS Lookups in Validation
The active_url rule and the dns option on the email rule perform real DNS queries, which makes any test that exercises them dependent on the network and prone to random failures. A new fakeDnsLookups() method skips the lookup while keeping the rest of the validation intact:
use Illuminate\Support\Facades\Validator; protected function setUp(): void{ parent::setUp(); Validator::fakeDnsLookups();}
Malformed URLs and email addresses still fail validation; only the network call is bypassed. Passing false turns the fake back off. Contributed by @SjorsO in #60879.
#[Delay] Attribute Support for Batches and Bulk Dispatch
Jobs that declare their delay with the #[Delay] attribute were delayed when dispatched individually, but Bus::batch() and Queue::bulk() only honored the $delay property and silently ignored the attribute. The queue drivers now check both, so the attribute behaves consistently across every dispatch path:
use Illuminate\Queue\Attributes\Delay; #[Delay(15)]class ProcessPodcast implements ShouldQueue{ use Queueable;} Bus::batch([new ProcessPodcast])->dispatch();
Contributed by @jackbayliss in #60766.
Multi-Queue Support in queue:clear
The queue:clear command now accepts comma-separated queue names, matching the convention already used by queue:work and queue:listen:
php artisan queue:clear redis --queue=high,low,emails
Whitespace is trimmed and duplicate names are removed before clearing. Contributed by @miladshakerdn in #60873.
Other Fixes and Improvements
- The
RateLimiterclass is now macroable (#60869), and theQueueFakeimplementscreationTimeOfOldestPendingJob()so code that inspects queue age runs underQueue::fake()(#60730) - HTTP fake responses accept PSR-7
StreamInterfaceinstances and PHP stream resources again, fixing a regression introduced by earlier body validation (#60834) - The
JobReleasedAfterExceptionevent now carries the exception that caused the release (#60823) - Fixed the queue name parameter in
Mailer::later()(#60865) and expiration handling inCache::touch()(#60878) - Restored iterable support in
Arr::every()andArr::some()(#60876) and inArr::last()(#60881) - HTTP testing credentials are marked as sensitive parameters so they stay out of stack traces (#60880)
Str::ucfirst()andStr::lcfirst()now use the native multibyte functions added in PHP 8.4 (#60864), and class attribute resolution now checks attributes declared on traits (#60566)
Upgrade Notes
No breaking changes are expected for typical applications. Keep in mind that #[BindWhen] relies on closures in attribute arguments, which requires PHP 8.5. Review the changelog for PR-by-PR details when upgrading.
References
- Official changelog
- Compare v13.21.1...v13.22.0
- PR: #60862 (
#[BindWhen]container attribute) - PR: #60879 (faking DNS lookups in validation)
- PR: #60766 (
#[Delay]attribute in batches and bulk dispatch) - PR: #60873 (multi-queue
queue:clear)