RabbitMQ
Message Queue
Data Migration
Technology
Software Tutorial

How to copy messages to another queue on RabbitMQ?

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Copying messages from one RabbitMQ queue to another is not a built-in queue-to-queue command in the way people often expect. RabbitMQ is designed around exchanges routing messages to queues, not around duplicating queue contents after the fact. The right solution depends on whether you want to duplicate future messages, migrate existing queued messages once, or bridge queues continuously between brokers.

For Future Messages, Fix the Routing

If the real goal is "send the same message to two queues from now on," do not copy messages out of a queue at all. Route them to both queues from the exchange.

For example, with a fanout exchange:

python
1import pika
2
3connection = pika.BlockingConnection(pika.ConnectionParameters("localhost"))
4channel = connection.channel()
5
6channel.exchange_declare(exchange="events", exchange_type="fanout", durable=True)
7channel.queue_declare(queue="queue_a", durable=True)
8channel.queue_declare(queue="queue_b", durable=True)
9
10channel.queue_bind(exchange="events", queue="queue_a")
11channel.queue_bind(exchange="events", queue="queue_b")
12
13channel.basic_publish(exchange="events", routing_key="", body=b"hello")
14connection.close()

That is the cleanest design because the message is duplicated at publish time rather than copied later by operational tooling.

For Existing Messages, Consume and Republish

If messages are already sitting in the source queue, a simple one-time migration tool is often easiest. The safe pattern is:

  1. consume from the source queue
  2. publish to the destination queue
  3. acknowledge the source message only after the destination publish succeeds

Example with pika:

python
1import pika
2
3connection = pika.BlockingConnection(pika.ConnectionParameters("localhost"))
4channel = connection.channel()
5
6channel.queue_declare(queue="source", durable=True)
7channel.queue_declare(queue="destination", durable=True)
8channel.confirm_delivery()
9
10for method_frame, properties, body in channel.consume("source", inactivity_timeout=1):
11    if method_frame is None:
12        break
13
14    channel.basic_publish(
15        exchange="",
16        routing_key="destination",
17        body=body,
18        properties=properties,
19        mandatory=True,
20    )
21    channel.basic_ack(method_frame.delivery_tag)
22
23channel.cancel()
24connection.close()

This keeps the message in the source queue until the republish succeeds. That matters if you are trying to avoid accidental loss.

Use Shovel for Operational Copying

RabbitMQ Shovel is a good operational tool when you want to move or forward messages continuously without writing code. It can read from one queue or broker and republish to another destination.

Shovel is especially useful for:

  • broker-to-broker forwarding
  • temporary migrations
  • cross-environment bridging

It is a better fit than a custom script when the job is long-lived or needs operational visibility. For a one-time local copy, a small consumer script is often simpler.

Avoid the HTTP API for Bulk Copying

RabbitMQ’s management HTTP API has a /get endpoint, but it is primarily an administrative or debugging tool, not the normal way to bulk copy queue contents.

Why it is a poor default:

  • it is easy to fetch messages in the wrong ack mode
  • it is not efficient for large transfers
  • it encourages manual copying logic outside normal AMQP workflows

If you do use it, pay very close attention to whether messages are requeued or acknowledged. A wrong setting can drain the source queue unexpectedly.

Be Clear About "Copy" Versus "Move"

This topic often hides an important requirement question.

If you want a copy:

  • source messages must stay available after the operation
  • destination gets duplicates

If you want a move:

  • source can be acknowledged and drained
  • destination becomes the new owner

The sample consumer above behaves like a controlled move, because it eventually acknowledges the source. A true copy requires leaving the source message in place or republishing future messages through exchange routing instead.

Common Pitfalls

The most common mistake is assuming a queue is the right place to duplicate traffic. In RabbitMQ, duplication is usually an exchange-routing concern, not a queue concern.

Another problem is acknowledging the source message before the destination publish has been confirmed. That creates a real message-loss window.

Developers also often forget that queue-level behavior such as TTL, dead-lettering, and max-length policies belongs to the destination queue, not to the copied message stream itself. Republishing into a new queue can therefore behave differently from the original.

Finally, avoid management API /get for high-volume migrations unless you have a very specific reason. AMQP consumers or Shovel are the better default tools.

Summary

  • For future duplication, bind multiple queues to the same exchange instead of copying after enqueue.
  • For existing messages, use a consumer that republishes and only then acknowledges the source.
  • Use RabbitMQ Shovel when you need an operational forwarding or migration tool.
  • Be explicit about whether you want a copy or a move.
  • Avoid bulk queue copying through the management HTTP API unless the scope is small and deliberate.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.