When dealing with event-driven or data streaming applications, there are a few concepts and vocabulary to introduce.

Messages, Payload, Metadata

A Message is an envelope around a payload. Your application is going to receive, process, and send Messages.

Your application’s logic can generate these Messages or receive them from a message broker. They can also be consumed by your application or sent to a message broker.


In Reactive Messaging, Message are represented by the Message class. Each Message<T> contains a payload of type <T>. This payload can be retrieved using message.getPayload():

String payload = message.getPayload();
Optional<MyMetadata> metadata = message.getMetadata(MyMetadata.class);

As you can see in the previous snippet, Messages can also have metadata. Metadata is a way to extend messages with additional data. It can be metadata related to the message broker (KafkaMessageMetadata for instance), or contain operational data (such as tracing metadata), or business-related data.

When retrieving metadata, you get an Optional as it may not be present.
Metadata is also used to influence the outbound dispatching (how the message will be sent to the broker).

Channels and Streams

Inside your application, Messages transit on channel. A channel is a virtual destination identified by a name.


SmallRye Reactive Messaging connects the component to the channel they read and to the channel they populate. The resulting structure is a stream: Messages flow between components through channels.

What about Reactive Streams?

You may wonder why Reactive Messaging has Reactive in the name. The Messaging part is kind of obvious. The Reactive part comes from the streams that are created by binding components. These streams are Reactive Streams. They follow the subscription and request protocol and implement back-pressure. It also means that Connectors are intended to use non-blocking IO to interact with the various message brokers.


Your application is interacting with messaging brokers or event backbone using connectors. A connector is a piece of code that connects to a broker and:

  1. subscribe/poll/receive messages from the broker and propagate them to the application

  2. send/write/dispatch messages provided by the application to the broker

Connectors are configured to map incoming messages to a specific channel (consumed by the application) and collect outgoing messages sent to a specific channel. These collected messages are sent to the external broker.


Each connector is dedicated to a specific technology. For example, a Kafka Connector only deals with Kafka.

You don’t necessarily need a connector. When your application does not use connectors, everything happens in-memory, and the streams are created by chaining methods altogether. Each chain is still a reactive stream and enforces the back-pressure protocol. When you don’t use connectors, you need to make sure the chain is complete, meaning it starts with a message source, and it ends with a sink. In other words, you need to generate messages from within the application (using a method with only @Outgoing, or an Emitter) and consume the messages from within the application (using a method with only @Incoming or using an unmanaged stream).