Headers Exchange in Depth
Discover the Headers exchange for routing messages based on header attributes instead of routing keys. Implement more complex and dynamic routing rules.
Headers Exchange in Depth is a free RabbitMQ Messaging & Async Systems lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the RabbitMQ Messaging & Async Systems learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Headers Exchange: New Routing
Meet the Headers exchange! Unlike Direct or Topic exchanges that use a simple routing_key string, Headers exchanges route messages based on their header attributes.
Think of it as a more flexible way to filter messages, using key-value pairs attached to the message itself.
Routing by Message Headers
When a producer sends a message, it includes a map of key-value pairs (headers). A consumer binds its queue to a Headers exchange with its own set of header rules.
The exchange then compares the message headers to the binding rules to decide where to deliver the message.
Matching Logic: 'all' or 'any'
Headers exchanges use a special argument called x-match in the binding to define the matching logic:
"all": The message's headers must contain all the key-value pairs specified in the binding."any": The message's headers must contain at least one of the key-value pairs specified in the binding.
This gives you powerful control over message delivery!
Producing with Custom Headers
Let's see how a producer adds custom headers to a message. We'll send a simple text message with format: json and type: report headers.
Run this code to send a message:
import com.rabbitmq.client.*;
import java.util.HashMap;
import java.util.Map;
public class HeadersProducer {
private static final String EXCHANGE = "my_headers_exchange";
public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
try (Connection conn = factory.newConnection();
Channel channel = conn.createChannel()) {
channel.exchangeDeclare(EXCHANGE, "headers");
Map<String, Object> headers = new HashMap<>();
headers.put("format", "json");
headers.put("type", "report"); // Add headers
String msg = "Report Data (JSON)";
AMQP.BasicProperties props = new AMQP.BasicProperties.Builder()
.headers(headers)
.build();
channel.basicPublish(EXCHANGE, "", props, msg.getBytes("UTF-8"));
System.out.println(" [x] Sent: '" + msg + "' with headers: " + headers);
}
}
}Consumer 'All' Match Example
This consumer will only receive messages if all its specified headers (format: json AND type: report) are present in the incoming message.
Run this consumer first, then the producer from the previous scene.
import com.rabbitmq.client.*;
import java.util.HashMap;
import java.util.Map;
public class HeadersConsumerAll {
private static final String EXCHANGE = "my_headers_exchange";
public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection conn = factory.newConnection();
Channel channel = conn.createChannel();
channel.exchangeDeclare(EXCHANGE, "headers");
String queueName = channel.queueDeclare().getQueue();
Map<String, Object> bindHeaders = new HashMap<>();
bindHeaders.put("x-match", "all");
bindHeaders.put("format", "json");
bindHeaders.put("type", "report"); // Requires both
channel.queueBind(queueName, EXCHANGE, "", bindHeaders);
System.out.println(" [*] Waiting for msgs with ALL: " + bindHeaders);
DeliverCallback dc = (ct, delivery) -> {
String msg = new String(delivery.getBody(), "UTF-8");
System.out.println(" [x] Received '" + msg + "' Headers: " + delivery.getProperties().getHeaders());
};
channel.basicConsume(queueName, true, dc, ct -> {});
}
}Consumer 'Any' Match Example
Now, let's create a consumer that receives messages if any of its specified headers (format: xml OR priority: high) are present.
Run this consumer. Then, try sending messages with different header combinations.
import com.rabbitmq.client.*;
import java.util.HashMap;
import java.util.Map;
public class HeadersConsumerAny {
private static final String EXCHANGE = "my_headers_exchange";
public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection conn = factory.newConnection();
Channel channel = conn.createChannel();
channel.exchangeDeclare(EXCHANGE, "headers");
String queueName = channel.queueDeclare().getQueue();
Map<String, Object> bindHeaders = new HashMap<>();
bindHeaders.put("x-match", "any");
bindHeaders.put("format", "xml"); // Matches if format is xml
bindHeaders.put("priority", "high"); // OR if priority is high
channel.queueBind(queueName, EXCHANGE, "", bindHeaders);
System.out.println(" [*] Waiting for msgs with ANY: " + bindHeaders);
DeliverCallback dc = (ct, delivery) -> {
String msg = new String(delivery.getBody(), "UTF-8");
System.out.println(" [x] Received '" + msg + "' Headers: " + delivery.getProperties().getHeaders());
};
channel.basicConsume(queueName, true, dc, ct -> {});
}
}More on `x-match` Values
While "all" and "any" are the primary x-match values, you can also omit x-match. If x-match is not provided, it defaults to "all".
Remember that the header values must match exactly. For example, "type": "report" won't match "type": "Report".
When to Use Headers Exchange
Headers exchanges are great for:
- Dynamic Routing: When routing logic changes often without code deployments.
- Complex Filtering: Routing based on multiple, non-hierarchical attributes.
- Policy-Based Routing: For example, routing high-priority messages to a dedicated queue.
It adds flexibility where routing keys might be too rigid.
Headers vs. Other Exchanges
How does Headers compare?
- Direct: Routes by exact
routing_keymatch. - Topic: Routes by
routing_keypatterns (wildcards). - Headers: Routes by arbitrary message header key-value pairs, offering more attribute-based flexibility.
Choose the exchange type that best fits your message routing needs!
Headers Exchange Quiz
A producer sends a message with headers {"color": "red", "size": "large"}.
Which consumer binding configuration(s) will receive this message?
Lesson Summary
In this lesson, we explored the powerful Headers exchange. You learned:
- It routes messages based on header key-value pairs.
- The
x-matchargument ("all"or"any") controls the matching logic. - How to use it for flexible, attribute-based message routing.
This exchange offers a robust alternative to routing keys for complex filtering scenarios.
Frequently asked questions
Is the “Headers Exchange in Depth” lesson free?
Yes — the full text of “Headers Exchange in Depth” is free to read here on the web, and the RabbitMQ Messaging & Async Systems course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the RabbitMQ Messaging & Async Systems course, upgrade to CoddyKit PRO.
What will I learn in “Headers Exchange in Depth”?
Discover the Headers exchange for routing messages based on header attributes instead of routing keys. Implement more complex and dynamic routing rules. You practise RabbitMQ Messaging & Async Systems with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start RabbitMQ Messaging & Async Systems?
No prior experience is required. RabbitMQ Messaging & Async Systems on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Headers Exchange in Depth” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this RabbitMQ Messaging & Async Systems lesson?
Yes. Every RabbitMQ Messaging & Async Systems lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Headers Exchange in Depth
- Exchange-to-Exchange Bindings
- Dead Letter Exchanges (DLX)
- Alternate Exchanges for Unroutable Messages