← All articles

Backpressure in Spring WebFlux, explained with a leaky bucket

2 min readJavaSpringWebFlux

Reactive code gets a reputation for being hard, and most of that reputation comes from one word: backpressure. It sounds like plumbing, and honestly, the plumbing metaphor is the fastest way to understand it.

A consumer that can't keep up

Imagine a producer pouring events into a bucket and a consumer draining it. If the producer pours faster than the consumer drains, the bucket overflows — in software terms, you get unbounded memory growth and, eventually, an OutOfMemoryError. Backpressure is the consumer telling the producer "slow down, I'll ask for more when I'm ready."

In Reactor, that conversation is built into the Publisher/Subscriber contract. A subscriber calls request(n) to signal how many items it can handle:

Flux.range(1, 1_000_000)
    .onBackpressureBuffer(256)        // bounded buffer, not infinite
    .publishOn(Schedulers.parallel())
    .subscribe(new BaseSubscriber<>() {
        @Override
        protected void hookOnSubscribe(Subscription s) {
            request(1);                // ask for one to start
        }

        @Override
        protected void hookOnNext(Integer value) {
            handle(value);
            request(1);                // ask for the next only when done
        }
    });

The subscriber pulls one item at a time. The producer can't get ahead of it, and the buffer is explicitly bounded — overflow becomes a decision (drop, error, latest) instead of a surprise.

Strategies you actually choose between

Operator What it does when overwhelmed
onBackpressureBuffer Queues items (optionally bounded)
onBackpressureDrop Discards items the consumer can't take
onBackpressureLatest Keeps only the most recent item

There's no universally correct choice — a metrics stream might prefer latest, an audit log must buffer and never drop. The point is that Reactor makes you decide, and that decision is where reliability lives.

When you don't need any of this

If your pipeline is request/response — one HTTP call in, one out — backpressure rarely matters; demand is naturally bounded by the single result. It earns its keep with streams: server-sent events, Kafka consumers, file processing, anything where a fast source meets a slower sink. Reach for it there, and leave the ceremony out of the simple paths.

Comments

Comments are powered by GitHub Discussions and aren't configured yet.

say.hola

Let's build something.

Hiring for a lead engineer, planning an AI initiative, or organizing a Java event — my inbox is open, in English o en español.

© 2026 Eimer Castro Hincapie — Medellín, Colombia