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, connection pooling, and DevServices.

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