---
question: When do I publish and when do I enqueue on the bus?
kind: overview
---

# Message bus

The bus service moves bytes between the parts of a project. It is the kernel service `services.bus`, with two delivery models: **publish** reaches every subscriber that is listening, **enqueue** hands each message to exactly one worker and keeps it until one takes it. The event service broadcasts through it, and so does the triple store.

Publishing and consuming are Python only. In NATS mode, super admins can browse the JetStream streams and their stored messages in Nexus, under System › Data › Bus. How the engine uses NATS as a whole is on [Message bus](/user-guide/get-started/nats) in Get started.

<!-- matrix -->

## Backends

| Adapter | Used when | Publish | Enqueue |
|---|---|---|---|
| `nats_jetstream` | NATS mode (a top-level `nats:` block). Always this one. | Core NATS subject `<topic>.<routing_key>` | A JetStream stream per topic (`naas-abi-<hash>`), one durable consumer per topic and routing key |
| `python_queue` | No `nats:` block. The default. | A SQLite file, kept 60 seconds for other processes to read | The same file, until a worker acknowledges. Without `persistence_path` (a block with `config: {}`), memory only: lost on restart |
| `rabbitmq` | No `nats:` block, legacy Docker stacks | A topic exchange, one exclusive queue per subscriber | A durable queue per topic and routing key |

In NATS mode, leave the `bus:` block out, or keep it only for `emit_message_events`, with `nats_jetstream` on the same URL as `nats.nats_url`. Any other adapter fails at start. The keys are on the [Configuration Reference](/user-guide/get-started/configuration#message-bus).

## Key concepts

- **Topic and routing key.** Every call names a topic and a routing key; the payload is `bytes`. A subscriber's routing key is a pattern: `.` separates segments, `*` matches one, a trailing `#` matches the rest. `#` alone matches everything on the topic.
- **Publish is live only.** Nothing is kept for a subscriber that was not connected. Use it to notify.
- **One model per topic.** Do not `publish` and `enqueue` on the same topic. In NATS mode a topic's work-queue stream captures `<topic>.>`, so once a queue exists, plain publishes on that topic are stored and handed to its workers.
- **Enqueue is durable.** A message waits until one worker takes it, across restarts (except on a `python_queue` without `persistence_path`). Workers on the same topic and routing key share it: each message goes to one of them. Use it for work that must happen once.
- **At least once.** A worker can see a message twice, after a crash or a failed acknowledgement. Make the work safe to repeat.
- **Large payloads.** In NATS mode, a payload above the broker limit travels as a claim check in the `abi_claim_checks` object store, up to 256 MiB. It expires after 7 days, so a queued item must be consumed within that time.
- **Events.** `services.bus.emit_message_events: true` records a `BusMessagePublished` or `BusMessageEnqueued` event for every message. It is off by default because the bus is high volume. A failed send always records `BusError`.
- **Dependency.** A module lists `BusService` in `ModuleDependencies.services`. The attribute is `self.engine.services.bus`.
