# Designing a Topology — RabbitMQ

Source: https://www.skillbyai.com/en/rabbitmq/d-topology

> Name and organise exchanges, queues and bindings for many services.

## A topology that grows cleanly

A clear topology makes a system understandable. Common conventions: **one exchange per domain or bounded context**, owned by the publishing team (`orders`, `payments`, `catalogue`), usually of type **topic**; **routing keys** that describe the event in a fixed shape, such as `<entity>.<event>.<region>` (`order.placed.in`); **one queue per consuming service and purpose**, named after the consumer (`billing.orders`, `email.orders`), so each service owns its queue, prefetch and scaling; and a **dead-letter exchange and parking-lot queue per consumer**. Publishers never declare consumers' queues; consumers declare (or request) their own queues and bindings. Keep **definitions in version control**: RabbitMQ can import and export a JSON **definitions file**, and tools like Terraform providers or the Kubernetes Messaging Topology Operator manage exchanges, queues, bindings, users and policies declaratively. Apply cross-cutting settings such as queue type, DLX, TTL and length limits through **policies** rather than hardcoding them in every client.

## Exchange per domain, queue per consumer

Each publishing domain owns an exchange; each consuming service owns its queue and dead-letter queue.

![Two diamonds on the left feeding arrows into four queue bars on the right, each queue bar followed by a smaller grey bar for dead letters.](assets/figures/rabbitmq/section-7-map.svg) — Figure 7.1 — A domain-oriented topology.

## A definitions file excerpt

Topology as code, importable at startup or through the management API.

```json
{
  "vhosts": [{ "name": "shop" }],
  "exchanges": [
    { "name": "orders", "vhost": "shop", "type": "topic", "durable": true },
    { "name": "billing.dlx", "vhost": "shop", "type": "fanout", "durable": true }
  ],
  "queues": [
    { "name": "billing.orders", "vhost": "shop", "durable": true,
      "arguments": { "x-queue-type": "quorum" } },
    { "name": "billing.orders.dead", "vhost": "shop", "durable": true,
      "arguments": { "x-queue-type": "quorum" } }
  ],
  "bindings": [
    { "source": "orders", "vhost": "shop", "destination": "billing.orders",
      "destination_type": "queue", "routing_key": "order.placed.*" },
    { "source": "billing.dlx", "vhost": "shop", "destination": "billing.orders.dead",
      "destination_type": "queue", "routing_key": "" }
  ],
  "policies": [
    { "vhost": "shop", "name": "billing-dlx", "pattern": "^billing\\.orders$",
      "apply-to": "queues", "definition": { "dead-letter-exchange": "billing.dlx", "delivery-limit": 5 } }
  ]
}
```

## Name for the reader at 3 a.m.

During an incident, `billing.orders` tells an on-call engineer who consumes the queue and what it holds. `queue_7` or `q-main` tells them nothing.

**Quiz:** In a domain-oriented topology, who usually owns a consumer queue such as billing.orders?

- [x] The billing team, which consumes from it
- [ ] The orders team, because it publishes the messages
- [ ] Nobody; queues are anonymous
- [ ] The database team

*Answer:* The billing team, which consumes from it. Each consuming service owns its queue, prefetch, scaling and dead-letter handling.
