# Addressing (/connectors/amqp/concepts/addressing)



The terminus address is the single most client-load-bearing fact about the KubeMQ AMQP 1.0
connector: it tells the connector **which KubeMQ pattern and channel** a link talks to. This
guide is the practical playbook for the `<pattern>/<channel>` grammar — always use explicit
prefixes — plus channel validation, longest-prefix matching, dynamic and anonymous addresses,
and the absence of vhosts.

For the address validation rules in table form, see
[Address mapping](/connectors/amqp/reference/address-mapping).

## Where the address goes [#where-the-address-goes]

AMQP 1.0 has no exchanges or routing keys. You choose the destination by setting a terminus
address on the link — and *where* it goes depends on the link role:

| You are…                                   | The address goes in…                                     |
| ------------------------------------------ | -------------------------------------------------------- |
| a **receiver** (you consume)               | the link **source** address                              |
| a **sender** to a fixed node (you produce) | the link **target** address                              |
| an **anonymous sender**                    | `properties.to` on **each message** (the target is null) |

## The grammar — always use explicit prefixes [#the-grammar--always-use-explicit-prefixes]

```text
address := [ "/" ] pattern "/" channel    # leading "/" is optional: queues/x ≡ /queues/x
        |  bare                            # no recognized prefix → JMS hint, else DefaultPattern
        |  "/responses/" RequestID         # RPC reply token (reply path only; server-receiver only)
        |  <dynamic>                       # source.dynamic / target.dynamic → _amqp10.tmp.<connID>.<uuid>
pattern := "queues" | "events" | "events-store" | "commands" | "queries"
```

| Terminus address             | KubeMQ pattern                                                                   | Channel                |
| ---------------------------- | -------------------------------------------------------------------------------- | ---------------------- |
| `queues/<ch>`                | queues                                                                           | `<ch>`                 |
| `events/<ch>`                | events                                                                           | `<ch>`                 |
| `events-store/<ch>`          | events-store                                                                     | `<ch>`                 |
| `commands/<ch>`              | commands                                                                         | `<ch>`                 |
| `queries/<ch>`               | queries                                                                          | `<ch>`                 |
| `responses/<RequestID>`      | responses (synthetic; RPC reply path only)                                       | the opaque reply token |
| bare (no prefix, no `/`)     | JMS node-capability hint (`queue`→queues, `topic`→events), else `DefaultPattern` | the bare string        |
| null target on a sender      | anonymous — routed per-message by `properties.to`                                | (per message)          |
| anything else containing `/` | **error** → `DETACH(amqp:not-found, "unknown address prefix")`                   | —                      |

The leading slash is optional and stripped: `queues/orders` ≡ `/queues/orders`. The prefix is
**stripped, never prepended** — the resolved channel (`orders`) is what the broker sees, so it
always passes the underlying channel validation.

<Callout type="info">
  **Always emit the explicit `<pattern>/<channel>` prefix.** It makes the destination
  deterministic and self-documenting: `queues/orders`, `events/telemetry`,
  `events-store/audit`, `commands/provision`, `queries/lookup`. Do not rely on bare addressing
  in fresh application code (see below).
</Callout>

## Longest-prefix matching [#longest-prefix-matching]

The connector matches prefixes **longest-first**: `events-store/` is tested **before**
`events/`. So `events-store/audit` resolves to the **events-store** pattern with channel
`audit` — it is never mis-read as the **events** pattern with channel `store/audit`. You never
need to escape or disambiguate; just write the full prefix. The full matching order is
`events-store → queues → events → commands → queries → responses`.

## Bare addressing — a Qpid-JMS migration convenience only [#bare-addressing--a-qpid-jms-migration-convenience-only]

A bare address (no recognized prefix and no `/`) is resolved **non-deterministically**:

1. If the terminus carries a JMS **node-capability hint**, it selects the pattern: `queue` →
   queues, `topic` → events.
2. Otherwise the connector's configured &#x2A;*`DefaultPattern`** applies (default `queues`).

This exists so a **migrating Qpid-JMS / ActiveMQ app** can point at KubeMQ by changing only the
connection string and the destination name — a JMS `Queue("orders")` carries the `queue`
capability and lands on `queues/orders` without an explicit prefix.

<Callout type="warn">
  Bare addressing is **non-deterministic and config-dependent**: the same bare name resolves
  differently depending on the client's capability hint and the broker's `DefaultPattern`. Treat
  it as a migration aid, not a design choice. For any fresh code, **use the explicit prefix** so
  the destination is unambiguous and survives a `DefaultPattern` change. A bare value that still
  contains a `/` is treated as an **unknown prefix**, not a bare channel →
  `DETACH(amqp:not-found, "unknown address prefix")`.
</Callout>

## Channel validation — stricter than the native layer [#channel-validation--stricter-than-the-native-layer]

After the prefix is stripped, the connector validates the channel **more strictly than the
underlying KubeMQ array layer**. A channel that works on the gRPC/native side can be rejected
over AMQP. A violation closes the link with `DETACH(amqp:not-found)`:

| Rejected channel               | Example                    |
| ------------------------------ | -------------------------- |
| empty                          | `queues/`                  |
| longer than **255** characters | `queues/<256+ chars>`      |
| has a &#x2A;*trailing `.`**    | `queues/orders.`           |
| contains **whitespace**        | `queues/my orders`         |
| contains `*` or `>` wildcards  | `queues/orders.*`          |
| contains `;` or `:`            | `queues/a:b`, `queues/a;b` |

<Callout type="info">
  A channel name that works on the native KubeMQ side can be **rejected over AMQP** because of
  the extra `;`, `:`, and trailing-`.` restrictions. Keep AMQP channel names to `[a-zA-Z0-9._-]`,
  ≤ 255 chars, with no trailing dot, and you are never surprised.
</Callout>

## Dynamic and anonymous addresses [#dynamic-and-anonymous-addresses]

These are special address forms the connector mints or routes specially.

### Dynamic nodes (`source.dynamic` / `target.dynamic`) [#dynamic-nodes-sourcedynamic--targetdynamic]

Attach a receiver with &#x2A;*`DynamicAddress: true`** (a dynamic source) and the connector creates a
fresh node and echoes its address in the reply `ATTACH`: `_amqp10.tmp.<connID>.<uuid>`. This is
the mechanism for an **RPC reply node** — a requester opens a dynamic receiver, reads back its
echoed address, and stamps it as `reply-to`. See
[Commands](/connectors/amqp/concepts/commands).

<Callout type="warn">
  Dynamic nodes are **node-local**: a temp node created on node A is not reachable from node B.
  RPC *replies* are still cluster-safe (they travel the broker reply path), but a direct
  cross-node send to a dynamic address is not.
</Callout>

### Anonymous terminus (null target sender) [#anonymous-terminus-null-target-sender]

A sender opened with a **null target** (`NewSender("", nil)`) is an *anonymous&#x2A; sender: it has no
fixed destination, and each message selects its destination via &#x2A;*`properties.to`** (which itself
uses the `<pattern>/<channel>` grammar). Because there is no fixed channel at attach,
authorization is deferred to a **per-message Write check** on each message's `to` (see
[Authentication](/connectors/amqp/how-to/authentication)). A bad `to` →
`amqp:precondition-failed`; a missing `to` → a Send error.

<Callout type="warn">
  The connector advertises **no `ANONYMOUS-RELAY` capability** — anonymous-terminus routing works
  by the connector inspecting `properties.to`, not by a capability handshake. Clients whose
  anonymous-producer API depends on `ANONYMOUS-RELAY` negotiation (notably **Qpid JMS**) cannot
  emit the single null-target link the connector routes on, so they cannot drive the anonymous
  terminus — use explicit per-pattern senders there instead.
</Callout>

### `/responses/` reply tokens [#responses-reply-tokens]

`/responses/<RequestID>` is a synthetic RPC reply address. It is **valid only as a
server-receiver attach** (the reply path); a **receiver** attach on `/responses/` →
`DETACH(amqp:not-allowed)`. You do not construct these yourself in normal use — the RPC layer
manages them, and they are connection-scoped (not authorized via Casbin).

## No vhost [#no-vhost]

AMQP 1.0 has **no vhost**. The `OPEN` `hostname` field (which a client carrying over a 0-9-1
mental model might set) is **logged then ignored**. There is no vhost option to expose and no
namespace scoping by hostname.

## Reaching AMQP 0-9-1 data [#reaching-amqp-0-9-1-data]

The AMQP 1.0 and AMQP 0-9-1 connectors **do not share a namespace**. AMQP 0-9-1 queues live on
KubeMQ channels named `amqp.<vhost>.<queue>`. To reach the same data from an AMQP 1.0 client,
use the explicit queues prefix over that channel name:

```text
/queues/amqp.<vhost>.<queue>
```

Cross-protocol equivalence holds the other way too: an AMQP 1.0 `queues/<ch>` maps to the bare
KubeMQ channel `<ch>`, so a gRPC/native client producing to `<ch>` interoperates with an AMQP
1.0 consumer of `queues/<ch>`.

## Quick reference [#quick-reference]

| Destination                  | Address to use                                                        |
| ---------------------------- | --------------------------------------------------------------------- |
| Queue `orders`               | `queues/orders`                                                       |
| Event stream `telemetry`     | `events/telemetry`                                                    |
| Durable event stream `audit` | `events-store/audit`                                                  |
| Command channel `provision`  | `commands/provision`                                                  |
| Query channel `lookup`       | `queries/lookup`                                                      |
| RPC reply node               | dynamic receiver (`DynamicAddress: true`); never a hand-built address |
| Route per-message            | anonymous sender + `properties.to = "queues/<ch>"` etc.               |
| AMQP 0-9-1 queue             | `/queues/amqp.<vhost>.<queue>`                                        |
| Fresh app code               | **always the explicit prefix** — never rely on bare addressing        |

## Related [#related]

<Cards>
  <Card title="Address mapping" href="/connectors/amqp/reference/address-mapping" description="The full grammar, channel-validation, and the Qpid-JMS anonymous-terminus limitation as reference tables." />

  <Card title="Authentication" href="/connectors/amqp/how-to/authentication" description="SASL identity and the per-message Write check on an anonymous sender's properties.to." />

  <Card title="Commands" href="/connectors/amqp/concepts/commands" description="How dynamic reply nodes and the /responses/ token drive request/reply over AMQP 1.0." />
</Cards>
