All Java templates

Vert.x with Mutiny (Reactive)

Mutiny Uni/Multi over the callback API — composable reactive workflows.

DevZone Tools880 copiesUpdated Mar 8, 2026Vert.xJava
# CLAUDE.md — Vert.x with Mutiny

## Why Mutiny

- **Mutiny** (`io.smallrye.mutiny:mutiny`) is a reactive library tightly integrated with Vert.x and Quarkus.
- Cleaner than callback Vert.x. More fluent than Vert.x `Future`. Reactive Streams compatible (interop with Reactor, RxJava).
- For new Vert.x code, prefer Mutiny or `Future`. Avoid the original callback API.

## Uni and Multi

- `Uni<T>` — 0..1 element with possible failure. Most use cases.
- `Multi<T>` — 0..N elements (a stream). For event streams, paginated reads, message subscriptions.

## Mutiny-flavored Vert.x

- Use `io.vertx.mutiny.*` packages — every Vert.x API has a Mutiny version returning `Uni`/`Multi`:
  ```java
  io.vertx.mutiny.core.Vertx vertx = io.vertx.mutiny.core.Vertx.vertx();
  io.vertx.mutiny.core.http.HttpClient client = vertx.createHttpClient();
  Uni<String> body = client.request(GET, "https://example.com").flatMap(req -> req.send().flatMap(HttpClientResponse::body)).map(Buffer::toString);
  ```
- Don't import the non-Mutiny `io.vertx.core.*` types in Mutiny code. The signatures don't compose.

## Common operators

- `.map(fn)` — synchronous transform.
- `.onItem().transformToUni(fn)` — async transform returning a `Uni`. Equivalent to `flatMap`.
- `.onFailure().recoverWithItem(default)` — fallback on error.
- `.onFailure().retry().atMost(3)` — retry the upstream up to N times.
- `.ifNoItem().after(Duration.ofSeconds(5)).fail()` — timeout.

## Combining Unis

```java
Uni<Result> combined = Uni.combine().all().unis(uniA, uniB)
    .with(Result::new);
```

- `combine().all()` for "wait for all". `combine().any()` for "first that completes".
- For collections: `Uni.combine().all().unis(listOfUnis).combinedWith(...)`.

## Subscribers

- Mutiny is **lazy**. The pipeline doesn't run until subscribed.
- In Vert.x Web with Mutiny: return `Uni<T>` from a handler — the framework subscribes for you.
- Manual: `uni.subscribe().with(item -> ..., failure -> ...)`.

## Backpressure (Multi)

- `Multi.createFrom().items(...)` for known finite streams.
- `Multi.createFrom().publisher(reactivePublisher)` for streams from another reactive lib.
- For backpressure: `.onOverflow().buffer(size)`, `.onOverflow().drop()`, etc. Choose based on what loss is acceptable.

## Error handling

- `onFailure()` selectors: `.onFailure(IOException.class).recoverWithUni(fallback)`.
- Always handle failures explicitly. Unhandled failures in `Uni` log a warning and disappear.
- Don't catch in the underlying lambda — let Mutiny carry the failure.

## Concurrency

- Mutiny respects the Vert.x event loop. Operators don't switch threads unless you ask.
- `.runSubscriptionOn(executor)` to subscribe on a specific executor.
- For blocking work inside a Uni chain: `.onItem().transformToUni(item -> Uni.createFrom().item(() -> blockingCall(item)).runSubscriptionOn(workerPool))`.

## Don't

- Don't mix Mutiny with raw Vert.x callbacks in the same chain. Convert at the boundary.
- Don't subscribe inside a handler — return the `Uni`.
- Don't `await().atMost(...)` on Unis in production code. That's blocking, defeating the purpose.
- Don't log inside `.map` lambdas — switch to `.invoke(item -> log.info(...))` for side-effect-only operators.

Other Java templates