Skip navigation

Netty 4.2 Migration Guide

Did you know this page is automatically generated from a Github Wiki page? You can improve it by yourself here!

Netty 4.2 Migration Guide

Netty 4.2 is largely backwards compatible with Netty 4.1, but there are a few choice compatibility breakages to be aware of, and a couple of new features worth knowing about.

From our (the Netty team) perspective, one of the biggest changes is that we are changing the minimum Java version requirement from Java 6 to Java 8. This upgrade is a big quality-of-life improvement for us, but it likely has no impact on anyone else because there are almost no regularly maintained Java projects left that still use Java versions older than Java 8.

Recommended upgrade process

The following is the recommended process for upgrading systems to Netty 4.2, that we have developed from practical experience. The process described here is high-level and generic, to accommodate a wide range of systems. Please read through the other sections of this migration guide, for details and tips that may be relevant to your specific system.

Before you begin, it is recommended that your systems use the dependency management best practices. Specifically, you should avoid shading as much as possible, since this process hides dependencies from dependency management tools like Maven and Gradle. You should also be using BOM files, such as netty-bom, to control your dependency versions. Following those practices will help you avoid ending up with a mix of versions at runtime.

The Netty 4.2 upgrade may take multiple sprints and deployment cycles, depending on the size and complexity of your systems. Plan accordingly, to ensure you have the time and resources to see the project through to its completion.

These are the recommended steps for upgrading to Netty 4.2:

  1. Upgrade to the latest Netty 4.1.x.
    Before you begin upgrading to Netty 4.2, make sure your systems are working correctly with the latest 4.1.x version.
  2. Ensure endpoint validation is explicitly configured for client TLS connections.
    In Netty 4.2, the default setting for endpoint validation (aka. hostname verification) changes. If you have TLS clients, make sure you explicitly configure endpoint validation to either on (recommended) or off (for niche use cases). The endpoint validation must be configured using the SslContextBuilder.endpointIdentificationAlgorithm(String) API that was added in Netty 4.1.112.
  3. Repeat step 1 and 2 for all your dependencies.
    It is important to ensure that all the components of your system is using the same Netty version, and are all configuring endpoint validation correctly. First off, this avoids any surprises from older client libraries that configure endpoint validation incorrectly, and may as a result stop working after a Netty 4.2 upgrade. Secondly, Netty 4.1 and 4.2 cannot co-exist on the class path, so you need to ensure you do the upgrade in a single step.
  4. Explicitly configure your system to use the pooled allocator.
    Netty 4.2 changes the default allocator to adaptive. To de-risk this change, it is recommended to first upgrade to 4.2 while explicitly configuring the pooled allocator, and then remove the allocator configuration as a second step. To explicitly configure the pooled allocator, set this system property: io.netty.allocator.type=pooled.
  5. Deploy your system with the above changes and make sure it works.
    The changes described in the steps 1 through 4 can all be deployed in one go, with the caveat that you may have libraries and frameworks on their own upgrade and release cycle. At this point, your system is still running Netty 4.1, but you are now ready for the 4.2 upgrade.
  6. Upgrade to the latest Netty 4.2.x, and deploy it.
    At this step, we just bump the Netty version to the last 4.2.x, and roll it out. Inspect your build and ensure that you have no Netty 4.1 dependencies left. As your build pipelines and deployments roll-out, watch out for errors related to endpoint validation in TLS clients, as this is the main risk for most systems. Once this is done and everything looks good, then you can choose to stop here if you are not interested in the adaptive allocator, otherwise you can proceed.
  7. Switch to the adaptive allocator.
    The adaptive allocator is the new default, but it is not necessary the best choice for everyone. It will be better for some workloads, and worse for others. If you have a load-test or soak-test environment, try the adaptive allocator there first. Simply remove the io.netty.allocator.type=pooled system property that we added in step 4. If it looks good, then proceed with deploying the change through your environments to production, and watch out for heap and direct memory usage and GC activity as the changes rolls out. If you see a significant increase in memory usage from the adaptive allocator, feel free to obtain a flight recording using our Netty Allocator Events.jfc recording profile, and open an issue about it with a recording attached. If the adaptive allocator is performing poorly for your workload, you can simply stay with the pooled allocator while we work to make the adaptive allocator better.

Following the above steps will give you a good chance at successfully upgrading to Netty 4.2, with few or no surprises.

Compatibility highlights

These are the most important compatibility breakages. The Netty team has done extensive validation testing of 4.2 in a number of large and high-profile projects, and these are the things that integrators are most likely to run into when upgrading their Netty dependencies from 4.1 to 4.2:

⚠️ For client TLS connections, we now enable hostname verification by default.

The SslContextBuilder.endpointIdentificationAlgorithm setting is now set to HTTPS by default, where in 4.1 it was null by default. Not doing hostname verification is obsolete and insecure practice from a more innocent time, that we haven't been able to change until now since suddenly enabling it could potentially break many systems.

This default can be overridden with a system property, to restore the Netty 4.1 behavior:

io.netty.handler.ssl.defaultEndpointVerificationAlgorithm=NONE

The purpose of this override is to aid systems with the Netty 4.2 migration. Systems that intentionally wish to disable endpoint identification should do so through the SslContextBuilder option.

⚠️ The adaptive memory allocator is now the default.

In Netty 4.1 the adaptive memory allocator was experimental. We have now made it the new default instead of the pooled allocator.

We believe that most workloads will observe reduced memory usage, with performance that is on par or slightly better than the pooled allocator. The adaptive allocator automatically tunes itself to perform well for the observed workload. It was also designed from the start to work well with virtual threads.

However, every application use their allocator in different ways, and stress them differently, so it is expected that the adaptive allocator will perform worse for some. Integrators who wish to keep using the pooled allocator like they did in Netty 4.1, can change the default allocator by setting this system property:

io.netty.allocator.type=pooled

⚠️ BouncyCastle upgrade.

We have updated our (still optional) BouncyCastle dependency. This is a breaking change because of how BouncyCastle versions their artifacts.

Our BouncyCastle dependencies have all changed from their *-jdk15on variants to their *-jdk18on variants.

This means that if you, for instance, are depending on both Netty and bcprov-jdk15on, then you will have to change which BouncyCastle artifact you depend on as part of your Netty 4.2 migration.

We have also upgraded the version we depend on from 1.69 to 1.80, which itself introduces compatibility breakages in their API.

⚠️ The netty-incubator-transport-io_uring module is no longer supported.

In Netty 4.2 we have graduated the io_uring transport from incubator, to a fully supported first-class transport module.

As part of this work, we have made numerous refactorings to the Netty transport internals that render the incubator version entirely incompatible. The good news is that netty-transport-native-io_uring is a much superior implementation thanks to these refactorings.

Integrators are encouraged to stop using the incubator module, and instead move to Netty 4.2 for its superior io_uring integration. Doing so will unfortunately require code changes. The following are things to watch out for:

  • The package name changes from io.netty.incubator.channel.uring to io.netty.channel.uring.
  • Class names are now prefixed IoUring instead of IOUring (note the lower-case ‘o’).
  • A number of io_uring channel options have changed.
  • IOUringEventLoopGroup does not exist anymore and is superseded by MultiThreadIoEventLoopGroup and IoUringIoHandler.
  • Usage of io_uring now requires Java9+.

Lesser compatibility changes

Netty 4.2 also includes a number of compatibility breakages that are less likely to cause problems, but needs to be mentioned regardless.

  • The protobuf-java dependency has received a major version bump from 2.6.1 to 3.25.5.
  • The netty-codec module has been split into a number of different sub-modules, which the netty-codec module then depends on. In other words, netty-codec is now multiple jar files instead of one.
  • We have dropped support for obsolete WebSocket draft specifications.
  • Dropped support for Jetty alpn/npn as ALPN is supported out of the box when using Java8.
  • The pipeline call-stack has been flattened, to reduce stack depths when processing messages through the pipeline. This may cause changes in behavior when messages are processed through the pipeline while the pipeline is concurrently modified, or when the pipeline makes use of child-executors.
  • The minimum required GLibC version is bumped from 2.12 (May 2010, e.g. CentOS 6) to 2.17 (December 2012, e.g. CentOS 7).
  • We are no longer testing our tcnative dynamic-linked OpenSSL integration with OpenSSL 1.0.1e (2013), and are now instead testing with OpenSSL 1.0.2k (2017).
  • Switched from automatic to real modules for JPMS.

The complete and exhaustive list of API breakages has been compiled by RevAPI: https://github.com/netty/netty/blob/3ca17a96cf84cbcb08776d3731b222b82814ead7/pom.xml#L1271-L7794

New best practices

Netty 4.2 introduces some new APIs, and deprecates some old APIs. As part of your migration to Netty 4.2, we encourage you to look through your code base for opportunities to clean up any use of deprecated APIs.

✅ IoHandlerFactories for EventLoopGroups

All transport-specific event loop groups, such as NioEventLoopGroup, have been deprecated.

Integrators should now instead pass a transport-specific IoHandlerFactory to a MultiThreadedEventLoopGroup constructor.

For example, stop doing this

EventLoopGroup group = new NioEventLoopGroup(); // ❌

and instead start doing this

EventLoopGroup group = new MultiThreadIoEventLoopGroup(NioIoHandler.newFactory()); // ✅

There is a static newFactory method for each of our transports:

  • NioIoHandler.newFactory()
  • EpollIoHandler.newFactory()
  • KQueueIoHandler.newFactory()
  • IoUringIoHandler.newFactory()
  • LocalIoHandler.newFactory()

Note that you must still configure the relevant channel or channel factory in your Bootstrap or ServerBootstrap instances.

✅ Extensibility of MultiThreadIoEventLoopGroup and SingleThreadIoEventLoop

The MultiThreadIoEventLoopGroup and SingleThreadIoEventLoop classes provide various methods that can be overridden by the user, and provide the ability to:

  • Get a count of registered channels / handles
  • Understand how long the IO processing vs task processing took
  • Get how many channels / handles were processed per loop run
  • Customize / decorate promises

Furthermore, it is now possible to register other things than Channels (as long as the correct IoHandle type is implemented), which provides a lot of possibilites to re-use netty components and also add support for other IoHandle implementations which does not exists as of today. For example, this could be used to implement file IO with io_uring.

✅ Use netty-pkitesting instead of SelfSignedCertificate

Netty 4.1 includes a SelfSignedCertificate class, which we use for testing our TLS implementation. This was not intended to be used as widely as it has ended up, and it suffers from a number of API decisions that make it a poor fit as a general purpose PKI and TLS testing tool.

In Netty 4.2 we are introducing a new module, netty-pkitesting, which includes a CertificateBuilder class. The CertificateBuilder is designed to allow integrators to test all sorts of PKI and TLS scenarios.

You can make self-signed certificates like before, or you can make proper CA, issuer, leaf certificate chains. The CertificateBuilder produces X509Bundle objects, which contain both certificate chains and the corresponding private key, and the bundles are created entirely in-memory without writing any files. If you need files for certificates, keys, or key stores, then the bundle objects include a number of convenient methods for creating temporary files for these.

The netty-pkitesting module also includes a simple Certificate Revocation List server, so you can test scenarios where certificates are revoked.

Last retrieved on 15-Aug-2025