The Problem Queue::forward() Solves
Queue names have a habit of spreading across your codebase. A job class sets onQueue('reports'), a dispatch call chains ->onConnection('redis'), a #[Queue] attribute pins another, and your worker configuration matches all of it. When you need to move that queue to a new Redis instance or rename it to satisfy a managed FIFO service, every one of those locations needs updating — including third-party packages you don't control.
Laravel 13.26 ships Queue::forward(), contributed by @jackbayliss in #61188. It lets you declare, in one place, that jobs dispatched to a given queue should land on a different queue, a different connection, or both.
The API
All signatures take a source queue and a destination:
use Illuminate\Support\Facades\Queue;
// Rename and move to another connection
Queue::forward('reports', 'reports.fifo', 'cloud');
// Keep the name, change the connection
Queue::forward('payments', connection: 'cloud');
// Rename on the same connection
Queue::forward('updates', 'notifications');
// Map several queues at once
Queue::forward([
'reports' => 'reports.fifo',
'emails' => 'emails.fifo',
], connection: 'cloud');
Queue names can be strings or backed enums. Register calls in a service provider's boot() method. Forwarding resolves through the same getConnection() hook that Queue::route() uses, so no new contract is required for custom drivers.
Important matching detail: a forward that specifies a connection only rewrites the queue name for jobs headed to that connection. A job explicitly dispatched to reports on redis keeps its name even if a forward targets reports on cloud. Forwards are a mapping, not a global find-and-replace.
Routing by Environment
Registering forwards in a provider makes environment-specific routing straightforward:
namespace App\Providers;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
if ($this->app->isProduction()) {
Queue::forward([
'reports' => 'reports.fifo',
'emails' => 'emails.fifo',
], connection: 'cloud');
}
}
}
Locally, dispatch(new GenerateReport) goes to reports on Redis as always. In production the identical code lands on reports.fifo on the managed connection. No environment checks inside job classes, no config/queue.php gymnastics.
The same pattern handles operational moves that previously required touching many files:
// Offload a heavy queue to a dedicated Redis instance
Queue::forward('encoding', connection: 'redis-heavy');
// Trial a new connection with one low-stakes queue
Queue::forward('notifications', connection: 'sqs-experiment');
Because a forward is one line, rolling back means deleting it — making gradual connection rollouts practical.
What Queue::forward() Does Not Do
- It applies at dispatch time only. Jobs already sitting on the old queue stay there. Drain the old queue with workers before retiring it.
- Do not run workers against both names long-term. The PR is explicit: once a forward is in place, treat the old queue name as deprecated and retire its workers after the drain to avoid race conditions.
- It does not pause or throttle consumption. For stopping consumption, use the queue pause API from Laravel 13.25.
- It does not reduce dispatch volume. If noisy listeners are the problem, this release also ships debounced queued listeners.
Key Takeaways
Queue::forward()centralises queue routing in a single service provider call.- Supports renaming, connection switching, or both — individually or in bulk.
- Works with strings and backed enums; no custom driver changes needed.
- Environment-conditional routing replaces scattered
onQueue()/onConnection()calls. - Applies only to newly dispatched jobs; drain old queues before retiring their workers.
Source: Queue::forward(): Reroute Laravel Queues in One Place — Laravel News