All Java templates

Spring WebFlux (Reactive)

Reactive Spring with Mono/Flux, R2DBC, backpressure, and non-blocking patterns.

DevZone Tools1,080 copiesUpdated Feb 22, 2026SpringJava
# CLAUDE.md — Spring WebFlux (Reactive)

## When to use WebFlux

- For high-concurrency I/O-bound services where you'd otherwise size a thread pool in the thousands.
- When the upstream APIs are reactive (e.g., R2DBC, MongoDB Reactive, reactive HTTP clients).
- **Don't** use WebFlux when:
  - The team isn't ready for reactive debugging (it's harder than imperative)
  - The DB driver is blocking (you'll wrap blocking I/O and lose every benefit)
  - Java 21+ is available — virtual threads on Spring MVC give similar concurrency without reactive complexity

## Mono and Flux

- `Mono<T>` for 0..1 elements. `Flux<T>` for 0..N elements.
- The pipeline doesn't run until something subscribes. WebFlux subscribes for you at the controller boundary.
- Don't call `.block()` in production code. It defeats the reactive model.

## Operators

- `.map(...)` — synchronous transform.
- `.flatMap(...)` — async transform that returns a `Mono`/`Flux`.
- `.zip(a, b)` — combine two parallel sources.
- `.then(...)` — chain a follow-up that doesn't depend on the result.
- `.switchIfEmpty(Mono.error(...))` — handle "no result" without `if`.

## Backpressure

- Built into Reactor. Slow consumers signal upstream to slow down.
- Configure `bufferSize`, `prefetch` on operators that aggregate. Default values are usually fine.
- For unbounded sources (event streams), always provide an overflow strategy (`onBackpressureBuffer`, `onBackpressureDrop`).

## R2DBC

- The reactive equivalent of JDBC. **Spring Data R2DBC** for repository-style access.
- Repositories return `Mono<T>` and `Flux<T>`. Methods named the same as JPA derived queries.
- No JPA. No lazy loading. Joins are explicit. Decide between `@Query` and projections per query.
- Transactions: `@Transactional` on a method returning a `Mono`/`Flux`. Reactor wires the lifecycle.

## Error handling

- `.onErrorResume(e -> Mono.just(fallback))` for recovery.
- `.onErrorMap(IOException.class, e -> new MyDomainException(e))` to translate.
- `@ExceptionHandler` in `@RestControllerAdvice` works the same as MVC. Use it for HTTP error mapping.

## Functional endpoints

- Alternative to annotated controllers: `RouterFunction<ServerResponse>` + `HandlerFunction`. Useful for very dynamic routing or pure-function-style codebases.
- For most apps, `@RestController` + `Mono`/`Flux` returns is simpler.

## Testing

- `@WebFluxTest` for controller slice tests. Provides `WebTestClient`.
- `StepVerifier` for assertions on `Mono`/`Flux`:
  ```java
  StepVerifier.create(service.find("id"))
      .expectNextMatches(u -> u.email().equals("a@b"))
      .verifyComplete();
  ```

## Don't

- Don't mix blocking JDBC/JPA with WebFlux. The first thing that blocks the event loop kills throughput.
- Don't subscribe inside a reactive pipeline. Return the publisher; let the framework subscribe.
- Don't `Flux.fromIterable(largeList)` for streaming — use a real reactive source from the start.
- Don't reach for WebFlux because "reactive is faster". It's a different model with different costs.

Other Java templates