Skip to content

Your First Queue

Let’s send one message through RabbitMQ. To keep it minimal we’ll use the default exchange — a nameless direct exchange that RabbitMQ provides automatically, where the routing key is simply the queue name. That lets us “publish straight to a queue” without declaring an exchange yet. (Every later lesson uses real named exchanges.)

First, run a broker locally with Docker:

Terminal window
docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management

Port 5672 is AMQP (for your app); 15672 is the management UI (open http://localhost:15672, log in with guest/guest).

The producer connects, opens a channel, declares a queue (so it exists), and publishes a message to it.

import amqp from 'amqplib';
const conn = await amqp.connect('amqp://localhost');
const channel = await conn.createChannel();
const queue = 'hello';
await channel.assertQueue(queue, { durable: false });
channel.sendToQueue(queue, Buffer.from('Hello, RabbitMQ!'));
console.log('sent: Hello, RabbitMQ!');
await channel.close();
await conn.close();

Note the empty exchange string ("") — that’s the default exchange, and the routing key is the queue name.

The consumer connects, declares the same queue (declaring is idempotent — safe to do on both sides), and subscribes. Its callback fires for each delivered message.

import amqp from 'amqplib';
const conn = await amqp.connect('amqp://localhost');
const channel = await conn.createChannel();
const queue = 'hello';
await channel.assertQueue(queue, { durable: false });
console.log('waiting for messages...');
channel.consume(queue, (msg) => {
if (msg) {
console.log('received:', msg.content.toString());
channel.ack(msg);
}
});
flowchart LR
  p["Producer
sendToQueue('hello')"] -->|default exchange| q["Queue: hello"]
  q -->|deliver| c["Consumer
prints + acks"]
The hello-world flow

The important details, small as they are:

  1. Both sides declare the queue. Declaring is idempotent and ensures the queue exists no matter who starts first.
  2. The message is just bytes. RabbitMQ doesn’t care about your format — string, JSON, protobuf, anything. Serialization is your job.
  3. The consumer acks. After processing, it tells RabbitMQ “done” so the message is removed. Skip this and you’ll get the message again on reconnect (which is exactly the safety you want — more in the acknowledgements lesson).
What is the "default exchange" used in the hello-world example?
Why do both the producer and consumer declare the queue?
What format must a message body be in?
What does the consumer's ack do?