Quarkus JMS Extension

The Quarkus JMS extension provides three complementary APIs for working with JMS:

  • JmsQueue<T> / JmsTopic<T> — injectable, typed destinations for sending and receiving messages

  • @JmsListener — annotation-driven message consumption

  • Reactive Messaging connector (smallrye-jms) — @Incoming / @Outgoing channel-based messaging

All three support local and XA distributed transactions and connection pooling.

This extension is in preview. Its API and configuration may still change based on feedback.
API Use when Example

JmsQueue<T> / JmsTopic<T>

Imperative send/receive in REST endpoints, services

Request-reply, browse, one-off sends

@JmsListener

Continuous message consumption

Order processing, event handling

RM connector (@Incoming/@Outgoing)

Reactive pipelines, stream processing

Channel-based messaging with backpressure

Getting Started

Add the extension to your project:

<dependency>
    <groupId>io.quarkiverse.jms</groupId>
    <artifactId>quarkus-jms</artifactId>
</dependency>

You also need a JMS provider. For example, the Quarkus Artemis JMS extension provides support for Apache Artemis:

<dependency>
    <groupId>io.quarkiverse.artemis</groupId>
    <artifactId>quarkus-artemis-jms</artifactId>
</dependency>

Quick Example

The following example shows a REST endpoint that sends orders to a JMS queue and a listener that processes them asynchronously.

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;

import io.quarkiverse.jms.JmsQueue;
import io.smallrye.common.annotation.Identifier;

@Path("/orders")
@ApplicationScoped
public class OrderResource {

    @Inject
    @Identifier("orders")
    JmsQueue<Order> orders;

    @POST
    public void placeOrder(Order order) {
        orders.message(order)
            .property("category", order.category())
            .send();
    }
}
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.persistence.EntityManager;

import io.quarkiverse.jms.JmsHeader;
import io.quarkiverse.jms.JmsListener;
import io.quarkus.logging.Log;

@ApplicationScoped
public class OrderProcessor {

    @Inject
    EntityManager em;

    @JmsListener(value = "orders", concurrency = 2)
    public void process(Order order, @JmsHeader("category") String category) {
        em.persist(order);
        Log.infof("Processed %s order %s", category, order.id());
    }
}

No connection or session management is needed — the extension handles session pooling, serialization, and lifecycle automatically. With quarkus-artemis-jms on the classpath, a broker is started via Dev Services and a ConnectionFactory is already configured out of the box.

What’s Next