Reactor Netty: Reactive TCP, HTTP, UDP and QUIC on Top of Netty
TCP/HTTP/UDP/QUIC client/server with Reactor over Netty
At a glance
- What is it?
- Reactor Netty wraps Netty's event loop in Reactor's Mono and Flux types so that HTTP, TCP, UDP and QUIC clients and servers can be written as non-blocking pipelines. It is a library for JVM engineers who already think in reactive terms, and it ships as separate core and HTTP artifacts.
- Who is it for?
- Adopt Reactor Netty if your application already exposes Reactor types and you need a client or server whose reads and writes honour backpressure, or if you want HTTP, TCP, UDP and QUIC behind one API surface. Do not adopt it if your stack is servlet-based, if you depend on blocking libraries inside handlers, or if you need the breadth of a full proxy toolkit rather than a client and server library.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Reactor Netty Is and Who It Is For
Reactor Netty is a library that offers non-blocking and backpressure-ready TCP, HTTP, UDP and QUIC clients and servers on top of the Netty framework. The unit of composition is Reactor: reads arrive as a Flux, a single write completes as a Mono. That is the whole pitch, and it defines the audience precisely. If your code already passes around Mono and Flux, Reactor Netty removes the impedance mismatch you get when a reactive application calls a callback-based or blocking network client. If your code does not use Reactor, the library adds a programming model you must learn before it adds any value.
The repository is split into modules rather than shipped as one jar. The top level contains reactor-netty-core, reactor-netty-http, reactor-netty-quic, reactor-netty-http-brave for tracing integration, reactor-netty-examples, and reactor-netty-graalvm-smoke-tests. The README's dependency example references two artifacts, io.projectreactor.netty:reactor-netty-core and io.projectreactor.netty:reactor-netty-http, which tells you the project expects you to pick the layer you need. A plain TCP or UDP service does not need the HTTP module on the classpath.
This matters for anyone deciding whether to adopt it. Reactor Netty is not a framework that owns your application lifecycle the way a servlet container does. It gives you a server object you bind and a client object you configure, and you keep control of threading. Spring Boot's reactive web stack builds on it, which is why a large share of its users encounter it indirectly. Direct users tend to be teams writing gateways, protocol clients, or services that need a raw TCP or UDP channel alongside HTTP.
How the Reactor-to-Netty Bridge Actually Works
Netty is an event loop framework. A small number of threads own channels, and every operation is expressed as a callback or a future. Reactor Netty sits between that model and your code. A server binds a channel, and each accepted connection is handed to a handler that receives a request object and a response object. The request's body is exposed as a Flux of buffers, and the response exposes a send method that accepts a publisher. Backpressure travels in both directions: if your consumer is slow, the demand signal propagates down to the socket read, and Netty stops reading from the channel. That is the mechanism the README means by backpressure-ready, and it is the main reason to prefer this over a plain Netty handler.
The README's HTTP example shows the shape of the API in a few lines. HttpServer.create() prepares a server, port(0) asks the system for an ephemeral port, route() declares a handler for POST requests under a path prefix with a path parameter, and bindNow() starts it in a blocking fashion. The handler calls response.sendString() with a publisher derived from request.receive().asString(), maps the body into a reply string, and logs it. On the client side, HttpClient.create() configures a client, post() and uri() select the method and path, send() takes a publisher for the request body, and responseContent().aggregate().asString().block() collects the reply. Note that only the client example blocks, and it does so at the edge of the pipeline, which is the normal pattern for a demonstration.
The QUIC module is worth calling out because it is not a rerun of the TCP stack. QUIC runs over UDP and carries its own stream multiplexing and encryption, so the module exists as a separate artifact rather than a flag on the TCP server. If you need HTTP/3, that is the module to look at. The http-brave module is a separate integration for distributed tracing, which suggests the maintainers prefer to keep instrumentation out of the core artifacts.
Installing Reactor Netty and Running a First Server
The README states that Reactor Netty requires Java 8 or later. Artifacts are published to Maven Central for stable releases and to repo.spring.io for snapshots and milestones. The README's Gradle example shows both artifacts, with the milestone version 1.4.0-M2 in the compile lines and commented-out snapshot lines above them. If you use Maven, the README points to the reference documentation for the equivalent coordinates rather than spelling them out.
A Gradle build that pulls the HTTP artifact looks like this. The repositories block names mavenCentral, and the dependency line names the artifact and version exactly as the README shows.
repositories {
mavenCentral()
}
dependencies {
compile "io.projectreactor.netty:reactor-netty-http:1.4.0-M2"
}With the dependency in place, the smallest useful server is the README's own example. It responds only to POST requests whose path starts with /test and then carries a path parameter, and it echoes the request body back with the parameter appended. Because the port is zero, the system assigns an ephemeral port at bind time, which is why the example can capture the bound server and read server.port() from it.
HttpServer.create()
.port(0)
.route(routes ->
routes.post("/test/{param}", (request, response) ->
response.sendString(request.receive()
.asString()
.map(s -> s + ' ' + request.param("param") + '!')
.log("http-server"))))
.bindNow();Calling bindNow() blocks until the server has finished initialising, so a process that reaches the next line knows the socket is open. To exercise it, the README pairs the server with a client that posts to /test/World and sends the body "Hello". The response body is aggregated and converted to a string, then block() pulls the value out for display. Expect the echoed payload to combine the sent string with the path parameter.
HttpClient.create()
.port(server.port())
.post()
.uri("/test/World")
.send(ByteBufFlux.fromString(Flux.just("Hello")))
.responseContent()
.aggregate()
.asString()
.log("http-client")
.block();If you would rather build from source, the README gives the commands. The build uses the Gradle wrapper and needs JDK 1.8, and publishToMavenLocal pushes the artifacts into your local Maven repository.
$ git clone https://github.com/reactor/reactor-netty.git
$ cd reactor-netty
$ ./gradlew build
$ ./gradlew publishToMavenLocalWhere Reactor Netty Is the Wrong Choice
The clearest limitation is the one the README implies by omission: every example is a pipeline, and blocking inside a handler is a mistake the library cannot prevent. If a handler calls a blocking JDBC driver or a synchronous HTTP client, it occupies an event loop thread, and because a small number of threads serve many connections, one slow call degrades unrelated traffic on the same loop. Reactor Netty does not detect this for you. Teams migrating from a thread-per-request server often carry blocking code with them, and the symptom is latency that appears under load rather than at development time.
The second constraint is scope. Reactor Netty is a client and server library, not a proxy or gateway toolkit. It does not ship routing DSLs beyond the predicate-based route builder shown in the README, and it does not ship the administrative surface you would expect from an application server. If what you actually need is a servlet container with session management, JSP support, or a deployment model, this is the wrong layer, and the reactive web stack on top of it is a different decision from adopting Reactor Netty directly.
Version selection is a real operational cost. The repository publishes milestones and snapshots alongside stable releases, and the README's own dependency snippet uses a milestone, 1.4.0-M2, with snapshot coordinates commented out above it. Milestones are not the same commitment as a stable release, and the README directs readers to the release notes for upgrade instructions and new and noteworthy features when upgrading. Anyone pinning a version should read those notes rather than assume API stability across the 1.3 and 1.4 lines. The README does not document rollback procedures, so downgrade behaviour is something you would have to establish for your own deployment.
Reactor Netty Compared with Plain Netty and with Servlet Containers
The most direct alternative is Netty itself. Reactor Netty is built on Netty, and the difference is the programming model rather than the transport. In plain Netty you write a ChannelInboundHandler and manage reference-counted buffers, and you implement flow control yourself through channel configuration and read suspension. Reactor Netty replaces the handler contract with a function that receives request and response objects, and it exposes bodies as publishers so that demand signalling is handled by the Reactive Streams machinery. The trade is control for composition: you give up direct access to some channel-level tuning in exchange for operators like map, aggregate and log working on the data stream.
Against a servlet container such as Tomcat or Jetty, the split is even wider. Those servers use a thread-per-request model, so blocking code is normal and the container sizes its thread pool to match. Reactor Netty assumes the opposite: few threads, non-blocking work, and backpressure instead of queueing. That is why the comparison questions people ask about Reactor Netty versus Tomcat or Jetty do not have a clean answer. A servlet container is the better fit when your dependencies block and you cannot change them. Reactor Netty is the better fit when your work is already asynchronous and you want the socket read to slow down when the consumer does.
There is also a practical difference in packaging. A servlet container is a deployment target you install; Reactor Netty is a library you embed, and the README's build instructions produce artifacts for your own build rather than a server distribution. The repository includes a GraalVM smoke test module, which signals that native image builds are a supported scenario the maintainers test against, something a traditional container deployment does not address in the same way.
Maintenance, Licensing and Upgrade Cost
The repository is not archived, and the last push was on 2026-09-24, four days before this article's reference point. Releases are frequent: v1.3.7 and v1.4.0-M1 both landed on 2026-08-24, and v1.4.0-M2 followed on 2026-09-24. That cadence means patch releases on the stable line arrive alongside milestones on the next line, so you can stay on a stable version while tracking what is coming. The README's support section points to a separate Support and Deprecation policy document in the reactor organisation, which is where deprecation timelines are defined rather than in the README itself.
Upgrade cost is concentrated in two places. The first is the version line: the README's example uses 1.4.0-M2, and the release notes are the stated source for upgrade instructions. The second is the module split. Because core and HTTP are separate artifacts, an upgrade can move one without the other, and a dependency management entry that pins only one of them can leave the pair out of step. The related search data shows people looking for a reactor netty bom, which is the usual answer to that problem, though the README does not document a BOM coordinate, so confirm it against the reference documentation before relying on it.
Licensing is straightforward on its face. Reactor Netty is released under the Apache License 2.0, which permits commercial use and modification and requires that you preserve notices. That is a permissive licence with no copyleft obligation on your own code, but the Apache 2.0 text also carries a patent grant and termination clause, and this article is not legal advice. If your organisation has a licence review process, the LICENSE file at the repository root is the authoritative copy.
Editorial conclusion
Adopt Reactor Netty if your application already exposes Reactor types and you need a client or server whose reads and writes honour backpressure, or if you want HTTP, TCP, UDP and QUIC behind one API surface. Do not adopt it if your stack is servlet-based, if you depend on blocking libraries inside handlers, or if you need the breadth of a full proxy toolkit rather than a client and server library. Before committing, verify which artifact you need (reactor-netty-core against reactor-netty-http), confirm the BOM or explicit version that matches your Spring Boot line, and read the release notes for the version you plan to run, because the repository publishes milestones such as v1.4.0-M2 alongside stable releases such as v1.3.7.
Frequently asked questions
What is Reactor Netty?
It is a library that provides non-blocking and backpressure-ready TCP, HTTP, UDP and QUIC clients and servers based on the Netty framework, with Reactor's Mono and Flux as the data types. It is split into modules such as reactor-netty-core, reactor-netty-http and reactor-netty-quic.
What is Reactor Netty used for?
It is used to build network clients and servers where reads and writes should honour backpressure, covering TCP, HTTP, UDP and QUIC. Because the API is built on Reactor types, it fits applications that already pass around Mono and Flux.
What is Reactor Netty HTTP?
It is the HTTP-specific module of the project, published as io.projectreactor.netty:reactor-netty-http. It provides the HttpServer and HttpClient types shown in the README's getting started example, separate from the core artifact that carries the lower-level transport support.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/reactor-reactor-netty)