NoSQL and Other Stores
|
This section documents Quarkus 3.39.x (current) with 3.33.x LTS as the production recommendation, on the Java 17+ baseline, as published at the official Quarkus guides — which are the reference these pages are written and verified against. Quarkus 4 raises the baseline to Java 21 (first release candidate planned for end of September 2026, see the Quarkus blog); readers upgrading past 3.39.x/3.33.x LTS should expect that change. This content was generated with the assistance of AI and should be verified against those official guides before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
This page is a Quarkus-integration survey of non-relational stores: for each store it covers only the Quarkus extension surface — client setup, configuration properties, Dev Services, and Panache-style helpers where one exists — not the underlying technology itself. For the data model, query language, indexing, clustering, and operational concerns of any of these stores, see Database Development and its per-technology reference pages.
MongoDB
Extension setup and configuration
quarkus-mongodb-client adds the MongoDB client and wires it into Quarkus’s configuration and health/metrics
infrastructure:
./mvnw quarkus:add-extension -Dextensions=mongodb-client
quarkus.mongodb.connection-string=mongodb://localhost:27017
quarkus.mongodb.database=bookstore
The native Java driver client and POJO codecs
A com.mongodb.client.MongoClient is injectable directly — the extension configures it from the
quarkus.mongodb.* properties above, including registering the driver’s PojoCodecProvider so plain Java
classes are read from and written to BSON documents automatically, with no hand-written codec or mapping
annotation required:
package com.example.book;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
@ApplicationScoped
public class BookMongoRepository {
@Inject
MongoClient mongoClient;
public MongoCollection<Book> collection() {
MongoDatabase database = mongoClient.getDatabase("bookstore");
return database.getCollection("books", Book.class);
}
public void insert(Book book) {
collection().insertOne(book);
}
}
package com.example.book;
public class Book {
public String title;
public String author;
public int publicationYear;
public Book() {
}
public Book(String title, String author, int publicationYear) {
this.title = title;
this.author = author;
this.publicationYear = publicationYear;
}
}
Book needs no annotation at all — the driver’s POJO codec maps its public fields (or getter/setter pairs) to
BSON fields by name, and back, on every read and write through collection().
MongoDB with Panache
quarkus-mongodb-panache layers an active-record API onto MongoDB that mirrors the shape of relational Panache
(quarkus-hibernate-orm-panache) — see Panache: The Quarkus Data API for the general Panache API shape
(list(), find(), persist(), and so on), which is not re-explained here:
package com.example.book;
import io.quarkus.mongodb.panache.PanacheMongoEntity;
public class Book extends PanacheMongoEntity {
public String title;
public String author;
public int publicationYear;
}
package com.example.book;
import java.util.List;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class BookService {
public List<Book> byAuthor(String author) {
return Book.list("author", author);
}
public Book create(String title, String author, int publicationYear) {
Book book = new Book();
book.title = title;
book.author = author;
book.publicationYear = publicationYear;
book.persist();
return book;
}
}
Dev Services for MongoDB
With quarkus-mongodb-client (or quarkus-mongodb-panache) on the classpath and no quarkus.mongodb.connection-string
configured, Dev Services automatically starts a MongoDB container for quarkus:dev and ./mvnw test, and
points quarkus.mongodb.connection-string at it — no manual container management, and no configuration
needed for local development or tests.
Redis
See the Redis Reference for Redis’s own data structures, persistence, and clustering model, beyond the Quarkus client surface covered here.
Extension setup and configuration
./mvnw quarkus:add-extension -Dextensions=redis-client
quarkus.redis.hosts=redis://localhost:6379
The high-level data-structure API: RedisDataSource
io.quarkus.redis.datasource.RedisDataSource exposes one typed, structure-specific command group per Redis
data structure — ValueCommands for strings, HashCommands for hashes, ListCommands for lists, and more — so calls stay type-safe instead of working with raw command names and untyped arguments:
package com.example.book;
import io.quarkus.redis.datasource.RedisDataSource;
import io.quarkus.redis.datasource.value.ValueCommands;
import io.quarkus.redis.datasource.hash.HashCommands;
import io.quarkus.redis.datasource.list.ListCommands;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
@ApplicationScoped
public class BookCacheService {
@Inject
RedisDataSource redisDataSource;
public void cacheTitle(String isbn, String title) {
ValueCommands<String, String> values = redisDataSource.value(String.class);
values.set(isbn, title);
}
public String cachedTitle(String isbn) {
ValueCommands<String, String> values = redisDataSource.value(String.class);
return values.get(isbn);
}
public void cacheDetails(String isbn, String author, String publicationYear) {
HashCommands<String, String, String> hash = redisDataSource.hash(String.class);
hash.hset(isbn, "author", author);
hash.hset(isbn, "publicationYear", publicationYear);
}
public void recordRecentlyViewed(String isbn) {
ListCommands<String, String> list = redisDataSource.list(String.class);
list.lpush("recently-viewed", isbn);
list.ltrim("recently-viewed", 0, 19);
}
}
Low-level commands via RedisCommands
Anything the high-level, structure-specific API does not cover — an uncommon command, or one added to Redis after the high-level API was written — is reachable through the data source’s untyped command execution:
package com.example.book;
import io.quarkus.redis.datasource.RedisDataSource;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
@ApplicationScoped
public class BookCacheAdminService {
@Inject
RedisDataSource redisDataSource;
public void expireTitle(String isbn, long seconds) {
redisDataSource.execute("EXPIRE", isbn, Long.toString(seconds));
}
}
Pub/sub via PubSubCommands
package com.example.book;
import io.quarkus.redis.datasource.RedisDataSource;
import io.quarkus.redis.datasource.pubsub.PubSubCommands;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
@ApplicationScoped
public class BookEventPublisher {
@Inject
RedisDataSource redisDataSource;
public void publishNewBook(String isbn) {
PubSubCommands<String> pubSub = redisDataSource.pubsub(String.class);
pubSub.publish("new-books", isbn);
}
public void subscribeToNewBooks() {
PubSubCommands<String> pubSub = redisDataSource.pubsub(String.class);
pubSub.subscribe("new-books", message -> System.out.println("New book: " + message));
}
}
Elasticsearch, OpenSearch, and Infinispan
Elasticsearch / OpenSearch: low-level REST client
quarkus-elasticsearch-rest-client (or quarkus-elasticsearch-java-client for the newer, typed Java API
client) gives direct access to the Elasticsearch/OpenSearch REST API for applications that build and run their
own requests rather than keeping an index synchronized with JPA entities:
./mvnw quarkus:add-extension -Dextensions=elasticsearch-rest-client
quarkus.elasticsearch.hosts=localhost:9200
Dev Services starts an Elasticsearch container automatically in dev/test mode when no
quarkus.elasticsearch.hosts is configured.
Hibernate Search ORM + Elasticsearch
quarkus-hibernate-search-orm-elasticsearch keeps a full-text index in Elasticsearch/OpenSearch automatically
in sync with Hibernate ORM entities: @Indexed marks an entity for indexing, and @FullTextField marks which
fields are analyzed and searchable, with no manual reindexing code required for ordinary entity writes:
package com.example.book;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed;
@Entity
@Indexed
public class Book {
@Id
@GeneratedValue
public Long id;
@FullTextField
public String title;
@FullTextField
public String synopsis;
}
package com.example.book;
import java.util.List;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import org.hibernate.search.mapper.orm.session.SearchSession;
@ApplicationScoped
public class BookSearchService {
@Inject
SearchSession searchSession;
@Transactional
public List<Book> search(String terms) {
return searchSession.search(Book.class)
.where(f -> f.match().fields("title", "synopsis").matching(terms))
.fetchHits(20);
}
}
Infinispan
quarkus-infinispan-client connects to a remote Infinispan cluster and exposes a RemoteCache<K, V> — Infinispan’s own client cache API shape — for typed put/get operations against a named cache:
./mvnw quarkus:add-extension -Dextensions=infinispan-client
quarkus.infinispan-client.hosts=localhost:11222
quarkus.infinispan-client.username=admin
quarkus.infinispan-client.password=changeme
package com.example.book;
import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.RemoteCacheManager;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
@ApplicationScoped
public class BookInfinispanCache {
@Inject
RemoteCacheManager remoteCacheManager;
public Book cachedBook(Long id) {
RemoteCache<Long, Book> cache = remoteCacheManager.getCache("books");
return cache.get(id);
}
public void cacheBook(Long id, Book book) {
RemoteCache<Long, Book> cache = remoteCacheManager.getCache("books");
cache.put(id, book);
}
}
Near-caching keeps a client-side copy of frequently-read entries so repeated reads avoid a round trip to the cluster; it is enabled per cache on the client configuration:
quarkus.infinispan-client.near-cache-max-entries=1000
Cassandra
The quarkus-cassandra-client extension wraps the DataStax Java driver and configures it from
quarkus.cassandra.* properties (quarkus.cassandra.contact-points, quarkus.cassandra.local-datacenter, and
so on); Cassandra’s own data-modeling concerns — partition keys, clustering columns, CQL — are not
Quarkus-specific and are not repeated here. See Database Development for Cassandra data modeling and
query design.
Quarkiverse-hosted stores
Several store integrations that used to ship as part of the core Quarkus platform have since moved to the
Quarkiverse organization — a set of community-maintained
Quarkus extensions with their own release cadence and support model, separate from first-party extensions
published under io.quarkus. Each still works the same way from an application’s point of view (an extension
dependency plus application.properties), but upgrading them tracks the Quarkiverse project’s own releases
rather than the core Quarkus BOM.
-
Neo4j (
io.quarkiverse.neo4j:quarkus-neo4j) — now Quarkiverse-hosted rather than a core Quarkus extension; see Neo4j Reference for the Neo4j reference itself. -
DynamoDB (
io.quarkiverse.amazonservices:quarkus-amazon-dynamodb) — part of the Quarkiverse Amazon Services extensions, not the core platform; see Database Development for key-value/wide-column data modeling guidance. -
Couchbase (
io.quarkiverse.couchbase:quarkus-couchbase) — Quarkiverse-hosted; see Couchbase Reference for the Couchbase reference itself.