June 1, 2026•9 min read•RabbitMQ tutorial

AMQP, short for Advanced Message Queuing Protocol, is an open, binary, application-layer protocol for passing messages between applications and services. It defines exactly how producers, brokers, and consumers talk to each other over the network, what a message looks like on the wire, and what guarantees the broker provides around delivery, ordering, and acknowledgment.
In other words: AMQP is the standardized "language" that message brokers and clients use to exchange data reliably across systems, languages, and platforms.
It's the protocol that powers RabbitMQ, Apache Qpid, ActiveMQ (via plugins), and several cloud-hosted message brokers.
Before AMQP, every message-broker vendor had its own proprietary protocol. If you wrote code against IBM MQ, TIBCO, or MSMQ, you were locked into that vendor's client libraries, tooling, and pricing.
AMQP was designed in 2003 by John O'Hara at JPMorgan Chase to solve this exact problem. The goal was simple:
The protocol was later standardized by OASIS, and AMQP 1.0 became an ISO/IEC standard (19464) in 2014.
This is the part that confuses most newcomers: there are two distinct versions of AMQP, and they are not compatible with each other.
AMQP 0-9-1 is the version implemented by RabbitMQ and by far the most widely deployed in the wild. It defines a rich, opinionated model with exchanges, queues, bindings, and routing keys built directly into the protocol.
If you've ever written code like this:
await channel.assertExchange("orders", "direct");
await channel.assertQueue("order.created");
await channel.bindQueue("order.created", "orders", "order.created");
channel.publish("orders", "order.created", Buffer.from("new order"));…you were speaking AMQP 0-9-1.
AMQP 1.0 is a complete redesign. It's a much thinner, more generic protocol that only defines how to move messages between two endpoints. Concepts like exchanges and queues are not part of AMQP 1.0; brokers expose those as implementation details.
AMQP 1.0 is used by Azure Service Bus, Apache Qpid, and Solace, among others. RabbitMQ supports AMQP 1.0 via a plugin, but its native protocol remains 0-9-1.
For the rest of this article, "AMQP" refers to AMQP 0-9-1 unless stated otherwise, since that's what RabbitMQ users encounter day-to-day.
AMQP follows the classic Producer → Broker → Consumer pattern, but with a twist: producers never send messages directly to queues. They send them to an exchange, and the broker routes them to one or more queues based on rules.
The full flow looks like this:
Producer → Exchange → Binding (routing key) → Queue → Consumer
This indirection is what gives AMQP its flexibility. Producers don't need to know which consumers exist or how many queues are interested in a message — they just publish to an exchange and let the broker figure out the rest.
A handful of building blocks make up the AMQP model. Understanding them is the key to using RabbitMQ effectively.
A connection is a long-lived TCP connection between a client and the broker. Opening and closing TCP connections is expensive, so AMQP encourages you to open one connection per application and reuse it.
Inside a connection, you create channels, which are lightweight virtual connections multiplexed over the single TCP socket. Channels are where the actual work happens: publishing, consuming, declaring queues, and so on. A typical app opens one channel per thread or per consumer.
An exchange is the routing layer. Producers always publish to an exchange, never directly to a queue. AMQP defines four exchange types, each with its own routing logic:
order.#, *.created.*)See RabbitMQ exchange types explained for animated examples of each one in action.
A queue is an ordered buffer that holds messages until a consumer is ready to process them. Queues can be:
A binding is a rule that links an exchange to a queue. Most bindings include a routing key, which the exchange uses (depending on its type) to decide whether a given message should be delivered to that queue.
An AMQP message has two parts:
content-type, delivery-mode (persistent vs transient), priority, expiration, correlation-id, custom headers, and moreWhen a consumer receives a message, it can either auto-ack (the broker assumes delivery the moment the message is sent) or manually ack after processing. Manual acks are what make AMQP reliable: if a consumer crashes mid-processing, the broker re-queues the message for another consumer.
For a deeper dive, see RabbitMQ message acknowledgment explained.
Here's the smallest possible round-trip using the Node.js amqplib client:
import amqp from "amqplib";
const connection = await amqp.connect("amqp://guest:guest@localhost:5672");
const channel = await connection.createChannel();
await channel.assertQueue("hello");
channel.sendToQueue("hello", Buffer.from("Hello AMQP!"));
await channel.consume("hello", (msg) => {
if (msg) {
console.log("Received:", msg.content.toString());
channel.ack(msg);
}
});Behind the scenes this opens a TCP connection on the default AMQP port 5672, negotiates the protocol version, opens a channel, declares a queue, publishes a message through the default exchange, and starts a consumer.
To make the guarantees concrete, here's what happens to a single message from publish to processing:
publish on an exchange with a routing key.If anything goes wrong — the consumer disconnects, the broker restarts, the network fails — AMQP's combination of durable queues, persistent messages, and manual acks ensures the message is either redelivered or dead-lettered rather than silently lost.
AMQP runs over TCP on a few well-known ports:
For production traffic, always use AMQPS. AMQP also supports SASL for authentication, so you can layer username/password, EXTERNAL (client certificate), or other mechanisms on top of the encrypted channel.
For the full list of ports RabbitMQ uses, see RabbitMQ default port and port configuration.
AMQP is one of several protocols you'll encounter in the messaging world. Here's how it compares.
MQTT is a lightweight publish/subscribe protocol designed for constrained devices and unreliable networks — think IoT sensors over cellular links. It has a tiny wire footprint and three simple QoS levels, but it lacks AMQP's richer routing model.
Use MQTT when you have thousands of small devices publishing telemetry. Use AMQP when you need flexible server-to-server routing with strong delivery guarantees.
RabbitMQ supports both protocols simultaneously, so you can bridge them.
STOMP (Streaming Text Oriented Messaging Protocol) is a simple, text-based protocol that's trivial to implement in any language — you can literally telnet into a broker and type STOMP frames by hand. It trades AMQP's features and binary efficiency for simplicity.
STOMP is great for browser clients (over WebSockets) and quick prototyping. AMQP is the better choice for production server-to-server messaging.
Kafka is not really a comparable protocol — it's a distributed commit log with its own custom binary protocol. Kafka excels at high-throughput event streaming and long-term retention, where AMQP excels at flexible routing, per-message acks, and request/reply patterns.
For a full breakdown, see RabbitMQ vs Kafka.
HTTP is synchronous and point-to-point. AMQP is asynchronous and many-to-many. If a service can be temporarily down, or if you want to fan out one event to many consumers, AMQP is the better fit. If you need an immediate, synchronous response, HTTP usually wins.
AMQP shines in scenarios where you need:
reply-to and correlation-id for RPC-style callsIf you're building an event bus or designing a system where reliability matters more than raw throughput, AMQP is almost always the right call.
One of the trickier parts of working with AMQP is that messages are invisible by default. They flow through exchanges and queues without leaving a trace, which makes debugging routing issues frustrating.
RabbitGUI gives you a live view of every exchange, queue, and binding in your broker, lets you publish test messages, and even lets you spy on real-time queue traffic without disturbing your production consumers. It's the easiest way to actually see your AMQP topology in motion.
AMQP solved a real problem: every message broker used to speak its own dialect, and switching vendors meant rewriting your application. By standardizing the wire format and the messaging model, AMQP turned message brokers into a commodity and made systems like RabbitMQ possible.
If you're just getting started, the best next step is to spin up a broker and send your first message. Our setup RabbitMQ with Docker and Docker Compose guide gets you running in a couple of minutes, and from there you can explore exchanges, queues, and the rest of the AMQP model hands-on.
RabbitMQ tutorialBuilding an event bus with RabbitMQLearn how to design a decoupled event bus using a RabbitMQ topic exchange, with practical routing key conventions, durable queues, and animated diagrams showing message flow.
RabbitMQ tutorialRabbitMQ Retry Pattern: How to Retry Failed MessagesLearn how to implement message retry patterns in RabbitMQ using dead-letter queues, delayed retries with TTL, and exponential backoff strategies.
RabbitMQ tutorialRabbitMQ exchange types explained with animationsLearn how RabbitMQ exchanges work and when to use each type. Covers direct, fanout, topic, and headers exchanges with practical examples and use cases.Debug, monitor, and manage RabbitMQ with a modern developer interface.
Available on Windows, Mac, and Linux.

ProductHow to spy on real-time queue traffic in RabbitMQ?Inspecting live messages flowing through a RabbitMQ queue is tricky because consuming is destructive. Learn how RabbitGUI creates a shadow queue to capture traffic without affecting your application.
ProductHow to predict when a RabbitMQ queue will be empty?A step-by-step explanation of how to estimate backlog drain time for a RabbitMQ queue, from naive division to linear regression with adaptive windowing.
ProductAnnouncing RabbitGUI 1.1: Now on Windows and LinuxRabbitGUI v1.1 brings native support for Windows, Linux, and Intel-based Macs, along with a built-in auto updater. Here's why this release matters.