Library / SDK
digitalpetri/modbus avatar
digitalpetri/modbus

digitalpetri Modbus: a typed Modbus client and server for Java 17

Modbus TCP, Modbus TCP Security, Modbus RTU on Serial, and Modbus RTU on TCP for Java 17+.

864 stars254 forksJavaEPL-2.0

At a glance

What is it?
digitalpetri Modbus is a Java library covering Modbus TCP, Modbus TCP Security over TLS, Modbus RTU on serial and RTU over TCP, with typed request and response PDUs and pluggable transports. Its distinguishing choice is that both client and server roles live in one library, with the transport layer isolated behind an interface so the same code runs over TCP or a serial port.
Who is it for?
Use digitalpetri Modbus when you have to talk to industrial devices from a JVM and you want typed requests instead of hand-assembled byte arrays, or when you need to expose Modbus data yourself. Do not expect it to cover the whole Modbus ecosystem, because it is one library for one protocol family and the vendor quirks live in the device manuals.
Can I use it commercially?
Yes, with conditions. EPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 6 days 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 October 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One library, four wire formats

digitalpetri Modbus is a Java 17 client and server library for four combinations: Modbus TCP, Modbus TCP Security using TLS, Modbus RTU over serial, and Modbus RTU over TCP. The description of what it provides names three things: typed request and response PDUs, pluggable transports and codecs, and both synchronous and asynchronous client operations. The typed PDUs are the part that changes how you write code, because a request is a Java object with named fields rather than a byte array you assemble yourself, and the response carries typed accessors. The transport abstraction is the part that changes how you deploy it, because the same client code runs over a TCP socket or a serial port depending on which transport you hand it.

What a read actually looks like

The README's example reads holding registers from a Modbus TCP device, and it is short enough to read as the shape of the API.

java
var transport = NettyTcpClientTransport.create(cfg -> cfg.setHostname("10.0.0.100"));
var client = ModbusTcpClient.create(transport);

try (var ignored = client.open()) {
  var response = client.readHoldingRegisters(1, new ReadHoldingRegistersRequest(0, 2));
  System.out.println("register bytes: " + HexFormat.of().formatHex(response.registers()));
}

Three things are worth noting. The transport is created through a factory that takes a configuration lambda, so hostname and port are set without a separate builder type. The client is opened in a try-with-resources block, so the underlying connection is closed when the block exits rather than needing an explicit shutdown. And the unit identifier and the request object are separate arguments, which matches how Modbus addresses work, where a unit ID identifies which device on the bus answers.

Three modules and why the split exists

Most applications depend on the transport module they use, and Maven brings in the core modbus module transitively, so the dependency graph stays small. The core modbus module holds the client and server APIs, the PDUs, the framing, the services and the transport interfaces. The modbus-tcp module provides Netty transports for Modbus TCP, TCP with TLS, and RTU over TCP. The modbus-serial module provides jSerialComm transports for Modbus RTU over a serial port. The practical effect is that a TCP application declares one dependency and gets the core with it, while a serial application declares a different one, and the code that builds requests does not change between them. The repository layout mirrors the modules with modbus, modbus-tcp and modbus-serial directories alongside a pom.xml and a modbus-tests directory.

The dependency you declare for TCP

For a Modbus TCP application the Maven coordinates are the ones you would expect.

xml
<dependency>
  <groupId>com.digitalpetri.modbus</groupId>
  <artifactId>modbus-tcp</artifactId>
  <version>2.1.6</version>
</dependency>

The group is com.digitalpetri.modbus and the artifact is modbus-tcp, and the version in the example matches the current release, v2.1.6 from 2026-08-08. The library is published to Maven Central under those coordinates, and the badge in the README points at the central search for the group. The installation and modules documentation page referenced from the README goes further, covering serial coordinates, Java requirements and module details, which is where you would look when your wiring is serial rather than TCP.

What each transport supports

The transport capability table is short and decisive. Modbus TCP supports client and server roles, with optional mutual TLS. Modbus RTU over serial supports client and server, with no TLS. Modbus RTU over TCP supports client and server, with optional mutual TLS. The pattern is the sensible one, since TLS is a TCP concept and a serial link has no certificates to present, but the optional qualifier on the TCP rows is the thing to notice: mutual TLS means both sides authenticate, which is a different requirement from encrypting the link one way. The README also points to a feature and transport matrix for typed function-code support, raw-PDU access and broadcast support, which is the document to check before you commit to a device with an unusual function code.

The documentation is organised as how-to, concept and reference

The documentation index lists every how-to, concept and reference page, and the structure tells you how to approach the library. The how-to pages are the tasks: reading and writing over Modbus TCP, communicating over serial RTU, securing a Modbus TCP client with TLS, exposing data over Modbus TCP as a server, configuring timeouts and reconnection, and troubleshooting communication. The concept pages are the mental models: start with the Modbus mental model if the relationship among data areas, unit IDs, PDUs and transports is unfamiliar, and use the addressing, unit IDs and data page before translating a device manual into requests. The reference pages are the API reference links for generated Javadocs. The ordering is deliberate, and the middle layer is the one people skip.

Where digitalpetri Modbus is the wrong choice

Four limits apply. It covers Modbus and nothing else, so a device that speaks a vendor protocol with a Modbus compatibility layer will still need that vendor's SDK. It is a JVM library, so a controller with no Java runtime cannot use it directly, though a server process beside the device can. The asynchronous operations are the ones to look at carefully before committing, because the synchronous and asynchronous APIs have different failure characteristics and the README does not spell out how a timeout during an asynchronous call surfaces. And while the typed PDUs remove a class of mistakes, they do not remove the semantic ones, since the address you put in the request is still yours to get right from the device manual, and the library has no way to tell a wrong register from a right one.

Editorial conclusion

Use digitalpetri Modbus when you have to talk to industrial devices from a JVM and you want typed requests instead of hand-assembled byte arrays, or when you need to expose Modbus data yourself. Do not expect it to cover the whole Modbus ecosystem, because it is one library for one protocol family and the vendor quirks live in the device manuals. Verify first which transport and function codes your devices actually use, since the feature and transport matrix is the document that answers that, and note that TLS is available for TCP but not for serial, and that the modular layout means you depend on modbus-tcp or modbus-serial depending on your wiring.

Frequently asked questions

What does the digitalpetri Modbus library support?

It is a Java 17 client and server library for Modbus TCP, Modbus TCP Security using TLS, Modbus RTU over serial, and Modbus RTU over TCP. It provides typed request and response PDUs, pluggable transports and codecs, and both synchronous and asynchronous client operations.

Which Maven module should a Modbus TCP application use?

The modbus-tcp module, with groupId com.digitalpetri.modbus and artifactId modbus-tcp. It provides Netty transports for Modbus TCP, TCP with TLS and RTU over TCP, and the core modbus module comes in transitively.

Does the library support TLS?

Yes for the TCP transports, where the capability table lists optional mutual TLS for both Modbus TCP and Modbus RTU over TCP. Modbus RTU over serial has no TLS support, since a serial link has no certificates to present.

How do I read holding registers with digitalpetri Modbus?

Create a transport such as NettyTcpClientTransport with the hostname, create the client with ModbusTcpClient, open it in a try-with-resources block, and call readHoldingRegisters with a unit identifier and a ReadHoldingRegistersRequest. The response exposes the register bytes through an accessor.

What licence is digitalpetri Modbus released under?

The Eclipse Public License 2.0, with the LICENSE.md file at the repository root. The latest release is v2.1.6 from 2026-08-08, preceded by v2.1.5 and v2.1.4.

Official sources

  1. digitalpetri/modbus on GitHub
  2. Issues
  3. License: EPL-2.0
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/digitalpetri-modbus.svg)](https://hysenlabs.com/projects/digitalpetri-modbus)

Was this useful?