Spring WebFlux (Reactive)
Reactive Spring with Mono/Flux, R2DBC, backpressure, and non-blocking patterns.
# 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
Modern Java Rules
Java 21+ defaults: records, sealed types, pattern matching, virtual threads, var.
Java Testing with JUnit 5
JUnit 5 + AssertJ + Mockito + Testcontainers — opinionated test conventions.
Java Virtual Threads & Concurrency
Project Loom virtual threads, structured concurrency, and modern concurrent patterns.
Java Build (Maven & Gradle)
Build conventions, dependency management, multi-module projects, and CI patterns.
Java Streams & Collections
Streams API, immutable collections, Collectors, and idiomatic data manipulation.