# How to Bind Queues to Exchanges with Specific Routing Keys in Kourier

> Learn to bind queues to exchanges with specific routing keys in Kourier using the queueBind() method for efficient message routing.

- Repository: [Guimauve Digital/kourier](https://github.com/guimauvedigital/kourier)
- Tags: how-to-guide
- Published: 2026-03-02

---

**To bind queues to exchanges with specific routing keys in Kourier, invoke the `queueBind()` method on an `AMQPChannel` instance, providing the queue name, exchange name, routing key string, and optional arguments map.**

The Kourier library provides a Kotlin-multiplatform AMQP client that abstracts RabbitMQ operations through the `AMQPChannel` interface. Understanding how to bind queues to exchanges with specific routing keys in Kourier is essential for directing messages from exchanges to the correct consumer queues based on routing logic.

## Understanding the queueBind API

The primary mechanism for creating bindings resides in the `AMQPChannel` interface defined in [`amqp-client/src/commonMain/kotlin/dev/kourier/amqp/channel/AMQPChannel.kt`](https://github.com/guimauvedigital/kourier/blob/main/amqp-client/src/commonMain/kotlin/dev/kourier/amqp/channel/AMQPChannel.kt) at lines 387-393.

### Method Signature and Parameters

The `queueBind` operation accepts four parameters that map directly to the AMQP protocol's Queue.Bind frame:

- **`queue`**: The name of the target queue that will receive messages.
- **`exchange`**: The name of the source exchange routing the messages.
- **`routingKey`**: The binding key or pattern used for routing decisions.
- **`arguments`**: Optional broker-specific arguments (typically `emptyMap()`).

When you call `channel.queueBind(queue, exchange, routingKey)`, the underlying implementation in `DefaultAMQPChannel` (located at [`amqp-client/src/commonMain/kotlin/dev/kourier/amqp/channel/DefaultAMQPChannel.kt`](https://github.com/guimauvedigital/kourier/blob/main/amqp-client/src/commonMain/kotlin/dev/kourier/amqp/channel/DefaultAMQPChannel.kt), lines 505-527) constructs a `Frame.Method.Queue.Bind` frame and transmits it to the broker via `writeAndWaitForResponse()`.

### Architectural Flow

1. **Client invocation**: Your code calls `channel.queueBind()` with the specific routing key.
2. **Frame construction**: `DefaultAMQPChannel` builds an AMQP Queue.Bind frame containing the parameters.
3. **Network transmission**: The frame travels to the broker through the established connection.
4. **Broker registration**: The broker creates the binding relationship in its routing table.
5. **Confirmation**: The broker returns a Queue.Bound response, which the client receives to confirm success.

## Routing Key Interpretation by Exchange Type

The semantics of the routing key parameter vary depending on the exchange type. The Kourier implementation respects standard AMQP 0-9-1 routing semantics as documented in [`docs/tutorials/topics.md`](https://github.com/guimauvedigital/kourier/blob/main/docs/tutorials/topics.md) (lines 27-38).

### Direct Exchange Bindings

For **direct exchanges**, the routing key must match exactly. When a publisher sends a message with `basicPublish(exchange, "error", ...)`, only queues bound to that exchange with the routing key `"error"` receive the message. This enables precise, point-to-point routing scenarios.

### Topic Exchange Wildcards

For **topic exchanges**, the routing key becomes a pattern string using dot notation. The Kourier library supports standard AMQP wildcards:

- **`*`** (asterisk): Matches exactly one word in the routing key.
- **`#`** (hash): Matches zero or more words.

For example, binding with `"kern.*"` captures `"kern.info"` and `"kern.error"`, while `"*.critical"` captures `"kern.critical"` and `"user.critical"`. The pattern `"#"` would match all routing keys.

## Code Examples

The test suite in [`amqp-client/src/commonTest/kotlin/dev/kourier/tutorials/TopicsTest.kt`](https://github.com/guimauvedigital/kourier/blob/main/amqp-client/src/commonTest/kotlin/dev/kourier/tutorials/TopicsTest.kt) (lines 92-99) demonstrates practical binding implementations.

### Binding to a Direct Exchange

```kotlin
val channel = connection.openChannel()

// Declare a direct exchange
channel.exchangeDeclare(
    name = "direct_logs",
    type = BuiltinExchangeType.DIRECT,
    durable = false,
    autoDelete = true,
    internal = false,
    arguments = emptyMap()
)

// Declare a server-named queue
val queueInfo = channel.queueDeclare()
val queueName = queueInfo.queueName

// Bind with specific routing key "error"
channel.queueBind(
    queue = queueName,
    exchange = "direct_logs",
    routingKey = "error"
)

```

### Binding to a Topic Exchange with Patterns

```kotlin
// Declare a topic exchange
channel.exchangeDeclare(
    name = "topic_logs",
    type = BuiltinExchangeType.TOPIC,
    durable = false,
    autoDelete = true,
    internal = false,
    arguments = emptyMap()
)

// Create an exclusive, temporary queue
val queue = channel.queueDeclare(
    name = "", 
    durable = false, 
    exclusive = true, 
    autoDelete = true
)

// Bind to kernel facility logs
channel.queueBind(
    queue = queue.queueName,
    exchange = "topic_logs",
    routingKey = "kern.*"
)

// Bind to all critical severity logs
channel.queueBind(
    queue = queue.queueName,
    exchange = "topic_logs",
    routingKey = "*.critical"
)

```

### Publishing to a Bound Queue

```kotlin
// This message matches both bindings above ("kern" + "critical")
channel.basicPublish(
    body = "Kernel panic!".toByteArray(),
    exchange = "topic_logs",
    routingKey = "kern.critical"
)

```

The broker routes this message to the queue because `kern.critical` satisfies both the `kern.*` and `*.critical` patterns simultaneously.

## Summary

- **Invoke `queueBind()`** on an `AMQPChannel` instance to create bindings, passing the queue name, exchange name, and routing key (or pattern).
- **Direct exchanges** require exact routing key matches, while **topic exchanges** support `*` and `#` wildcards for flexible pattern matching.
- The implementation resides in [`DefaultAMQPChannel.kt`](https://github.com/guimauvedigital/kourier/blob/main/DefaultAMQPChannel.kt) (lines 505-527), which constructs and transmits AMQP Queue.Bind frames to the broker.
- Use empty arguments maps for standard bindings, or provide broker-specific options when required.

## Frequently Asked Questions

### What parameters does the queueBind method require?

The `queueBind` method requires three mandatory parameters: `queue` (the target queue name), `exchange` (the source exchange name), and `routingKey` (the binding key or pattern). It also accepts an optional `arguments` parameter of type `Map<String, Any>` for broker-specific extensions, though this is typically passed as `emptyMap()` for standard bindings.

### How do topic exchange wildcards work in Kourier?

Kourier implements standard AMQP 0-9-1 wildcard semantics where `*` matches exactly one dot-separated word and `#` matches zero or more words in a routing key. For a routing key `kern.critical`, the pattern `kern.*` matches because "critical" is one word, and `*.critical` matches because "kern" is one word. The pattern `#` alone would match any routing key.

### Where is the queueBind implementation located in the source code?

The interface definition exists in [`amqp-client/src/commonMain/kotlin/dev/kourier/amqp/channel/AMQPChannel.kt`](https://github.com/guimauvedigital/kourier/blob/main/amqp-client/src/commonMain/kotlin/dev/kourier/amqp/channel/AMQPChannel.kt) at lines 387-393. The concrete implementation that builds the AMQP frame and handles the network transmission lives in [`amqp-client/src/commonMain/kotlin/dev/kourier/amqp/channel/DefaultAMQPChannel.kt`](https://github.com/guimauvedigital/kourier/blob/main/amqp-client/src/commonMain/kotlin/dev/kourier/amqp/channel/DefaultAMQPChannel.kt) at lines 505-527.

### Can I bind the same queue to an exchange multiple times with different routing keys?

Yes. As shown in the topic exchange example, you can call `queueBind()` multiple times on the same queue and exchange combination with different routing keys. The queue will then receive any message that matches at least one of the bound routing keys or patterns, enabling flexible message consumption strategies.