Queue::forward(): Reroute Laravel Queues in One Place
Laravel #Laravel #Queues #Laravel 13.26 #PHP #Queue Routing

Queue::forward(): Reroute Laravel Queues in One Place

3 min read Mohamed Said Mohamed Said

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

Found this useful?

Frequently Asked Questions

3 questions
Q01 Does Queue::forward() affect jobs already sitting in the queue?
No. Queue::forward() applies only at dispatch time, so jobs already on the old queue remain there. You need to drain the old queue with workers before retiring it. Running workers against both the original and forwarded queue names long-term can cause race conditions.
Q02 Can I use Queue::forward() to route queues differently per environment?
Yes. Because forwards are registered in a service provider's boot() method, you can wrap them in environment checks such as $this->app->isProduction(). This lets the same job dispatch code land on a local Redis queue in development and a managed FIFO queue in production without any changes to job classes.
Q03 Does Queue::forward() require changes to custom queue drivers?
No. Forwarding resolves through the same getConnection() hook that Queue::route() already uses, with the rename applied by each driver's own queue resolution. There is no new contract for custom drivers to implement.

Continue reading

More Articles

View all