Difficulty: beginner
Estimated Time: 15 minutes

In this scenario, you will get an introduction to Hibernate Reactive with Panache, one of the many features of Quarkus.

What is Panache?

Hibernate is the de facto JPA implementation and offers you the full breadth of an Object Relational Mapper. It makes complex mappings possible, but many simple and common mappings can also be complex. Hibernate Reactive with Panache focuses on making your entities trivial and fun to write and use with Quarkus, while allowing fully-reactive and non-blocking access to relational databases.

With Panache Reactive, we took an opinionated approach to make Hibernate Reactive as easy as possible. Hibernate Reactive with Panache offers the following:

  • By extending PanacheEntity in your entities, you will get an ID field that is auto-generated. If you require a custom ID strategy, you can extend PanacheEntityBase instead and handle the ID yourself.

  • By using Use public fields, there is no need for functionless getters and setters (those that simply get or set the field). You simply refer to fields like Person.name without the need to write a Person.getName() implementation. Panache will auto-generate any getters and setters you do not write, or you can develop your own getters/setters that do more than get/set, which will be called when the field is accessed directly.

    • There is also a repository pattern that can be used as well. In this pattern the entity class does not extend any base class.
  • The PanacheEntity superclass comes with lots of super useful static methods and you can add your own in your derived entity class, and much like traditional object-oriented programming it's natural and recommended to place custom queries as close to the entity as possible, ideally within the entity definition itself. Users can just start using your entity Person by typing Person, and getting completion for all the operations in a single place.

  • You don't need to write parts of the query that you don’t need: write Person.find("order by name") or Person.find("name = ?1 and status = ?2", "stef", Status.Alive) or even better Person.find("name", "stef").

That’s all there is to it: with Panache, Hibernate Reactive has never looked so trim and neat.

Other possibilities

Learn more at quarkus.io, or just drive on and get hands-on!

In this scenario, you learned about Quarkus and Hibernate Reactive with Panache, and how it can be used to create supersonic, subatomic Java applications with simplified Hibernate queries. Quarkus provides an effective solution for running Java in this new world of serverless, microservices, containers, Kubernetes, FaaS, and the cloud because it has been designed with these in mind.

Its container-first approach for cloud-native Java applications unifies imperative and reactive programming paradigms for microservices development and offers an extensible set of standards-based enterprise Java libraries and frameworks combined with extreme developer productivity that promises to revolutionize the way we develop in Java.

Additional Resources

If you’re interested in helping continue to improve Quarkus, developing third-party extensions, using Quarkus to develop applications, or if you’re just curious about it, please check out these links:

Reactive Data access with Quarkus Hibernate Reactive with Panache

Step 1 of 6

Define Entity

In this step, you will start with a simple RESTful application generated from the Quarkus tooling, and then define a new entity to work on, which will be persisted in a typical database through the Quarkus Reactive SQL Clients, used by Hibernate Reactive under the covers.

Inspect Java runtime

An appropriate Java runtime has been installed for you. Ensure you can use it by running this command:

If the command fails, wait a few moments and try again (it is installed in a background process and make take a few moments depending on system load).

$JAVA_HOME/bin/java --version

The command should report the version in use, for example (the versions and dates may be slightly different than the below example):

openjdk 11.0.10 2021-01-19
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.10+9)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.10+9, mixed mode)

Import the code

Let's refresh the code we'll be using. Run the following command to clone the sample project:

cd /root/projects && rm -rf rhoar-getting-started && git clone https://github.com/openshift-katacoda/rhoar-getting-started

Inspect project

Make sure you're in the right project directory by clicking:

cd /root/projects/rhoar-getting-started/quarkus/panache-reactive

Initially, the project is almost empty and doesn't do anything. Start by reviewing the content by executing a tree in your terminal.

As you can see, there are some files that we have prepared for you in the project. Under src/main/resources/META-INF/resources we have for example prepared an html file for you, and some skeletal model files and utilities. This matches what you might get when generating sample projects using the Quarkus Project Generator.

We need to add a few extensions to the app for Panache Reactive and the reactive Postgres driver. We'll use the Quarkus Maven Plugin.

Click this command to add the Hibernate ORM with Panache and PostgreSQL JDBC extensions:

mvn quarkus:add-extension -Dextensions="hibernate-reactive-panache, reactive-pg-client"

You should see:

[SUCCESS] ✅ Extension io.quarkus:quarkus-hibernate-reactive-panache has been installed
[SUCCESS] ✅ Extension io.quarkus:quarkus-reactive-pg-client has been installed


There are many more extensions for Quarkus for popular frameworks like Eclipse Vert.x, Apache Camel, Infinispan, Spring DI compatibility (e.g. @Autowired), and more.

For more detail on basic Quarkus usage, check out the Getting Started scenario. We'll assume you've worked through that and understand the basics of a Quarkus app.

Define the entity

This app will be a database of people, each of which have a name, birthdate, and eye color. We'll need an entity, so open up the src/main/java/org/acme/person/model/Person.java file, and add the following entity definition:

package org.acme.person.model;

import java.time.LocalDate;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;

import io.quarkus.hibernate.reactive.panache.PanacheEntity;
import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;

public class Person extends PanacheEntity {
    // the person's name
    public String name;

    // the person's birthdate
    public LocalDate birth;

    // the person's eye color
    @Column(length = 8)
    public EyeColor eyes;

    public Person() {

    public Person(String name, LocalDate birth, EyeColor eyes) {
        this.name = name;
        this.birth = birth;
        this.eyes = eyes;

    // TODO: Add more queries

You'll see a // TODO line - do not delete it! We will use this later on.

As you can see we've defined the three fields name, birth, and eyes. We're using the Java Persistence API's @Enumerated field type for our eye color.

We'll also need the definition of eye colors, so let's create an enum. Open up the src/main/java/org/acme/person/model/EyeColor.java file, and add the following enum definition:

package org.acme.person.model;

public enum EyeColor {

Define the RESTful endpoint

Next, we'll create a PersonResource class which we will use for our RESTful endpoint. Open up that file by clicking: src/main/java/org/acme/person/PersonResource.java and click Copy To Editor to add its code:

package org.acme.person;

import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import javax.enterprise.event.Observes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

import org.acme.person.model.DataTable;
import org.acme.person.model.EyeColor;
import org.acme.person.model.Person;

import io.quarkus.hibernate.reactive.panache.Panache;
import io.quarkus.hibernate.reactive.panache.PanacheQuery;
import io.quarkus.panache.common.Parameters;
import io.quarkus.runtime.StartupEvent;
import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;

public class PersonResource {

    public Uni<List<Person>> getAll() {
        return Person.listAll();

    // TODO: add basic queries

    // TODO: add datatable query

    // TODO: Add lifecycle hook


You'll see a lot of // TODO lines - do not delete them! We will use these later on.

As you can see we've implemented our first Panache-based query, the getAll method, which will return our list of people as a JSON object when we access the GET /person endpoint. This is defined using standard JAX-RS @Path and @GET and @Produces annotations.

Add sample data

Let's add some sample data to the database so we can test things out. Open up the src/main/resources/import.sql file and click to add some SQL statements to run on startup:

INSERT INTO person(id, name, birth, eyes) VALUES (nextval('hibernate_sequence'), 'Farid Ulyanov', to_date('1974-08-15', 'YYYY-MM-dd'), 'BLUE');
INSERT INTO person(id, name, birth, eyes) VALUES (nextval('hibernate_sequence'), 'Salvador L. Witcher', to_date('1984-05-24', 'YYYY-MM-dd'), 'BROWN');
INSERT INTO person(id, name, birth, eyes) VALUES (nextval('hibernate_sequence'), 'Huỳnh Kim Huê', to_date('1999-04-25', 'YYYY-MM-dd'), 'HAZEL');

These statements will add some fake people to our database.