# Quarkus Patterns

> When to activate: Quarkus, native image, CDI, Panache, reactive, RESTEasy, GraalVM, health checks, Quarkus config

- Skill: `mattakushi432/quarkus-patterns` (Agent Skill)
- Install (CLI): `npx skillmds@latest add mattakushi432/quarkus-patterns`
- Raw SKILL.md: https://api.skillmd.com/api/skills/mattakushi432/quarkus-patterns/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Mattakushi432 (https://skillmd.com/u/mattakushi432)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/mattakushi432/quarkus-patterns

---

# Quarkus Patterns

## REST Resource

```java
@Path("/api/v1/products")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ProductResource {

    @Inject
    ProductService productService;

    @GET
    @Path("/{id}")
    public Product getProduct(@PathParam("id") Long id) {
        return productService.findById(id)
            .orElseThrow(() -> new NotFoundException("Product " + id + " not found"));
    }

    @POST
    @Transactional
    public Response createProduct(@Valid CreateProductRequest request) {
        Product product = productService.create(request);
        return Response.created(URI.create("/api/v1/products/" + product.id)).entity(product).build();
    }

    @GET
    public List<Product> list(@QueryParam("page") @DefaultValue("0") int page,
                               @QueryParam("size") @DefaultValue("20") int size) {
        return Product.findAll().page(page, size).list();
    }
}
```

## Panache Entity (Active Record)

```java
@Entity
@Table(name = "products")
public class Product extends PanacheEntity {
    @NotBlank
    public String name;

    @Positive
    public BigDecimal price;

    @Enumerated(EnumType.STRING)
    public ProductStatus status = ProductStatus.ACTIVE;

    public static List<Product> findActive() {
        return list("status", ProductStatus.ACTIVE);
    }

    public static Optional<Product> findBySlug(String slug) {
        return find("slug", slug).firstResultOptional();
    }
}
```

## Panache Repository

```java
@ApplicationScoped
public class ProductRepository implements PanacheRepository<Product> {

    public List<Product> findByCategory(String category) {
        return list("category = ?1 AND status = ?2", category, ProductStatus.ACTIVE);
    }

    public Page<Product> findPaged(int page, int size) {
        return findAll().page(Page.of(page, size));
    }
}
```

## CDI Scopes & Injection

```java
@ApplicationScoped          // singleton per app
@RequestScoped              // one per HTTP request
@Dependent                  // default — lifecycle of injecting bean
@SessionScoped              // one per session (CDI sessions)

@ApplicationScoped
public class EmailService {
    @Inject
    @ConfigProperty(name = "app.smtp.host")
    String smtpHost;

    @Inject
    Event<UserCreatedEvent> userCreatedEvent;

    public void sendWelcome(User user) {
        userCreatedEvent.fire(new UserCreatedEvent(user));
    }
}
```

## Reactive REST with Mutiny

```java
@Path("/api/v1/orders")
public class OrderResource {

    @Inject
    OrderService orderService;

    @GET
    public Multi<Order> streamOrders() {
        return orderService.streamAll();
    }

    @POST
    public Uni<Response> placeOrder(@Valid PlaceOrderRequest request) {
        return orderService.place(request)
            .map(order -> Response.created(URI.create("/orders/" + order.id)).entity(order).build());
    }
}
```

## Configuration

```java
@ConfigMapping(prefix = "app")
public interface AppConfig {
    String name();
    DatabaseConfig database();
    FeatureFlags features();

    interface DatabaseConfig {
        String url();
        int maxPoolSize();
    }

    interface FeatureFlags {
        boolean newCheckout();
    }
}
```

## Health Checks

```java
@Liveness
@ApplicationScoped
public class AppLivenessCheck implements HealthCheck {
    @Override
    public HealthCheckResponse call() {
        return HealthCheckResponse.up("app-live");
    }
}

@Readiness
@ApplicationScoped
public class DatabaseReadinessCheck implements HealthCheck {
    @Inject
    @ConfigProperty(name = "quarkus.datasource.jdbc.url")
    String jdbcUrl;

    @Override
    public HealthCheckResponse call() {
        // probe DB
        return HealthCheckResponse.named("database").up().build();
    }
}
```

## application.properties

```properties
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=${DB_USER}
quarkus.datasource.password=${DB_PASS}
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/mydb
quarkus.hibernate-orm.database.generation=validate

quarkus.http.port=8080
quarkus.log.level=INFO
quarkus.log.category."com.example".level=DEBUG

# Native image
quarkus.native.container-build=true
quarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-mandrel-builder-image:jdk-21
```

## Build Commands

```bash
# Dev mode with hot reload
./mvnw quarkus:dev

# JVM build
./mvnw package

# Native build (requires GraalVM or Docker)
./mvnw package -Pnative
./mvnw package -Pnative -Dquarkus.native.container-build=true
```

## Key Rules
- Use `@Transactional` on resource methods or service methods that mutate — not on Panache entity static methods
- Prefer `PanacheEntity` (Active Record) for simple domains; `PanacheRepository` when you need to decouple
- All Panache operations outside a transaction throw — always wrap mutations
- Use `Uni`/`Multi` for reactive endpoints; don't block the event loop with synchronous I/O in reactive mode
- Native image: register reflection classes in `@RegisterForReflection`; test native before shipping

