This episode connects Quarkus to a database: Hibernate ORM and Panache, entity mapping, the repository pattern, datasource and connection pooling configuration, as well as the in-memory H2 database for development mode.

A REST API without data storage is just a toy. Episode 6 takes your application to the next level: storing and reading data from a database. Quarkus integrates Hibernate ORM — the JPA (Jakarta Persistence) standard — with Panache to eliminate boilerplate.
Panache offers two popular patterns: active record and repository. You'll also learn datasource configuration, connection pooling, and how to use H2 as an in-memory database for development without installing a database server.
Panache is a layer on top of Hibernate ORM that makes entities and queries very concise. Its three main features:
PanacheRepository for the separate repository pattern.Add the extensions first:
./mvnw quarkus:add-extension \
-Dextensions=hibernate-orm-panache,jdbc-h2The command ./mvnw quarkus:add-extension -Dextensions=hibernate-orm-panache,jdbc-h2 adds Hibernate ORM with Panache and the JDBC driver for H2 in one go.
An active record entity extends PanacheEntity, which already provides an id field of type Long:
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import io.quarkus.hibernate.orm.panache.PanacheEntity;
@Entity
@Table(name = "items")
public class Item extends PanacheEntity {
public String nama;
public String deskripsi;
public double harga;
}Without getters and setters, you read and write fields directly: item.nama = "Laptop". This is a far more concise pattern than classic JPA.
Sometimes you need explicit mapping for tables with different column names or relationships:
import jakarta.persistence.*;
@Entity
@Table(name = "items")
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Long id;
@Column(name = "nama_item", nullable = false, length = 100)
public String nama;
@Column(name = "harga", precision = 12, scale = 2)
public double harga;
}Note: this class doesn't extend PanacheEntity, so you manage @Id yourself. Using @Column gives you full control over column names and constraints.
To separate data access logic from the entity, use PanacheRepository:
import io.quarkus.hibernate.orm.panache.PanacheRepository;
import jakarta.enterprise.context.ApplicationScoped;
import java.util.List;
@ApplicationScoped
public class ItemRepository implements PanacheRepository<Item> {
public List<Item> cariBerdasarkanNama(String keyword) {
return list("nama like ?1", "%" + keyword + "%");
}
}The list("nama like ?1", ...) method uses PanacheQL — a simpler JP-QL dialect. The repository is injected into the resource with @Inject.
The repository is injected into the resource with @Inject, then uses the built-in PanacheRepository methods: itemRepository.persist(item) to save a new entity and listAll() to fetch all data. Custom methods like cariBerdasarkanNama are called the same way.
Quarkus uses Agroal as its built-in connection pool. An H2 datasource configuration for development:
quarkus.datasource.db-kind=h2
quarkus.datasource.jdbc.url=jdbc:h2:mem:belajar
quarkus.datasource.username=sa
quarkus.datasource.password=
quarkus.hibernate-orm.database.generation=drop-and-create
quarkus.hibernate-orm.log.sql=truedb-kind=h2 tells Quarkus the database type.database.generation=drop-and-create creates the schema automatically at startup (development only).log.sql=true shows the SQL queries in the console — very helpful for debugging.The pool is managed automatically by Agroal. Common configuration:
quarkus.datasource.jdbc.min-size=1
quarkus.datasource.jdbc.max-size=20
quarkus.datasource.jdbc.acquisition-timeout=10SFor production, pay attention to max-size and acquisition-timeout so your application doesn't run out of connections during traffic spikes.
H2 runs in memory, with no server installation. It's ideal for development and testing because every application restart gives you a clean database. Quarkus also offers Dev Services: set quarkus.datasource.db-kind=postgresql without a URL, and with Docker running, Quarkus automatically starts PostgreSQL in a container while in dev mode — a real database with no manual setup.
Run ./mvnw quarkus:dev then test the API with curl:
curl -X POST http://localhost:8080/api/items -H "Content-Type: application/json" -d '{"nama":"Laptop","deskripsi":"Laptop developer","harga":15000000}' sends a new item.curl http://localhost:8080/api/items reads the list of stored items.You can also see the SQL queries Hibernate executes in the dev mode console.
Episode 6 connects your Quarkus application to a database: understanding Hibernate ORM and Panache with the active record and repository patterns, entity and column mapping, datasource and Agroal connection pool configuration, as well as using H2 and Dev Services for development.
Key takeaways:
PanacheEntity provides an automatic id field.PanacheRepository gives built-in CRUD methods like persist and listAll.quarkus.datasource.db-kind determines the database type.drop-and-create for quick schemas.In episode 7 we'll cover validation and request handling — Jakarta Bean Validation with @Valid and constraint annotations, request and response filters, interceptors, and exception translation for cleaner errors.