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 Spring templates
Spring Framework Core Rules
Dependency injection, bean lifecycle, configuration classes, and profiles.
Spring Data JPA
Repositories, derived queries, custom JPQL, projections, and N+1 prevention.
Spring Security Rules
SecurityFilterChain (no WebSecurityConfigurerAdapter), OAuth2 resource server, JWT.
Spring MVC Rules
Controllers, ResponseEntity, validation, exception handling, and content negotiation.
Spring Boot 3 Modern Rules
Boot 3+ defaults: starters, configuration properties, profiles, and structured logging.