All Quarkus templates

Quarkus + Hibernate ORM with Panache

Active-record and repository styles with Panache, Flyway migrations, transactions.

DevZone Tools1,340 copiesUpdated Mar 28, 2026QuarkusJavaJakarta EE
# CLAUDE.md — Quarkus + Hibernate ORM with Panache

## Pick a style

- **Active record**: entity extends `PanacheEntity` and exposes `find()`, `persist()`, `count()` directly on the class.
- **Repository**: separate `PanacheRepository<E>` class; entities stay POJOs.
- Pick one per project. Mixing is confusing.
- For DDD-style codebases, repositories are usually the right call. For CRUD apps, active record is faster to write.

## Entities

- Use records-friendly entity patterns:
  ```java
  @Entity
  public class User extends PanacheEntity {
      public String email;
      public String name;
      public Instant createdAt = Instant.now();
  }
  ```
- Public fields are fine — Panache rewrites them to property accessors at build time.
- Use `@Id` + `@GeneratedValue` only if you need a custom ID strategy. Default is `Long id`.

## Queries

- Derived queries via static methods on the entity (active record):
  ```java
  public static List<User> findByEmail(String email) { return list("email", email); }
  ```
- Or via repository methods:
  ```java
  @ApplicationScoped
  public class UserRepository implements PanacheRepository<User> {
      public List<User> findByEmail(String email) { return list("email", email); }
  }
  ```
- Use `find(...)` for lazy queries, `list(...)` for eager. `firstResult()` / `singleResult()` to materialize.
- Pagination: `find("...").page(Page.of(0, 20)).list()`.

## Transactions

- `@Transactional` on the service method. Don't put it on entities or repositories.
- Reads don't need a transaction unless they touch lazy collections — use `@Transactional` defensively if you're not sure.
- For **reactive Panache**, use `@WithTransaction` on `Uni`-returning methods.

## Migrations

- **Flyway** (`quarkus-flyway`) or **Liquibase** (`quarkus-liquibase`). Pick one.
- `quarkus.flyway.migrate-at-start=true` for dev. In production, run migrations as a separate step.
- Don't rely on `quarkus.hibernate-orm.database.generation=update` outside dev — it's not safe for production.

## DTO projection

- For list views, project to a DTO instead of returning entities:
  ```java
  public static List<UserListDto> listUsers() {
      return find("select new com.app.UserListDto(id, email) from User").project(UserListDto.class).list();
  }
  ```
- Avoid loading associations you don't render.

## Reactive variant

- Use `quarkus-hibernate-reactive-panache` for non-blocking DB access.
- Pair with `vertx-pg-client` driver. SQL drivers are blocking and won't work.
- Methods return `Uni<T>` and `Multi<T>`. Lifecycle integrates with RESTEasy Reactive endpoints.

## Don't

- Don't use Panache active record for CRUD-heavy domain models with rich behavior. They get crowded fast.
- Don't put query logic in resources. Push it to the entity (active record) or repository.
- Don't share the same entity class between two databases. Use separate persistence units.
- Don't use the blocking and reactive Panache variants in the same project.

Other Quarkus templates