# Apache PLC4X: one API layer across PLC protocols

> An Apache project that gives Java, Go, C, Python and .NET code a single way to talk to industrial PLCs, with protocol drivers living in one protocols/ directory. Only Java and Go are described as usable today, and the extras ship as a separate release.

**apache/plc4x** — PLC4X The Industrial IoT adapter

- Repository: https://github.com/apache/plc4x
- Website: https://plc4x.apache.org/
- Stars: 1,759 · Forks: 512
- Language: Java
- License: Apache-2.0
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/apache-plc4x

## Uniform access is the whole pitch, and it is unevenly delivered

Apache PLC4X states its goal plainly: a set of libraries for communicating with industrial grade programmable logic controllers in a uniform way, so that an application does not carry a vendor-specific driver for every machine on the floor. The repository is a multi-language effort, with top-level directories named plc4j, plc4go, plc4c, plc4py and plc4net, plus a shared protocols/ directory that holds the protocol implementations.

The language list in the README is honest in a way most project pages are not. Java and Go are shipped. C is marked not ready for usage, Python is marked not ready for usage, and C#/.NET is marked not ready for usage with the extra word abandoned in parentheses. That last marker is the one to read twice, because it describes a binding that is still in the tree and still wired into the build while not being worked on.

The repository's default branch is develop rather than main, which is normal for an Apache project but does mean a casual clone lands on integration work rather than the last release. The last push was on 2026-10-15.

## Java 21 is a hard floor, not a preference

The README is specific: the minimum Java version is Java 21, tested up to Java 24. At least Java 21 is required to build all parts of the plc4x-extras repository. That is a floor, and it matters for anyone whose build environment is pinned to an older long-term release.

The developer prerequisites are listed separately. A Java 21 JDK is needed to run Maven and to compile the Java modules, with JAVA_HOME pointing at it. Git is required even when working from the source distribution. Two optional items gate the full test suite: libpcap or Npcap for the raw socket tests and passive-mode drivers, and Docker for the tests that use Testcontainers. Building the website needs network access to kroki.io, because the documentation diagrams are rendered there at build time rather than by local tooling.

The project is split into three repositories: plc4x, plc4x-build-tools and plc4x-extras. That last one holds both the integration modules and the two servers, so a consumer who wants the extras has to track a second artifact stream.

## The build breaks on a submodule unless you pass the add-exports flags by hand

There is a build trap worth documenting in full, because it is the kind of thing that costs an afternoon. The code generation uses a utility that needs extra VM settings. A build from the root picks them up automatically from .mvn/jvm.config. A build of a single submodule does not, and fails until you supply the flags yourself.

```text
--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
```

In IntelliJ these belong under Preferences | Build, Execution, Deployment | Build Tools | Maven | Runner: JVM Options. There is one mitigation for the underlying problem: on a full build the project runs a prerequisite check and fails with an explanation of what to do, rather than with a raw compiler error. Partial builds get no such courtesy, which is exactly why the flags are spelled out in the README.

If you would rather not deal with the JDK flags at all, the Docker path exists. The Dockerfile is based on azul/zulu-openjdk:21 and the compose file drives a full build with the profile set that enables every language and check.

## What the extras release actually contains

Three Java-side pieces carry most of the practical value, and all three are released as part of plc4x-extras rather than the core.

The OPC-UA Server lets a legacy device be reached through OPC-UA using PLC4X, so consumers that only speak OPC-UA can read a Modbus or S7 machine without knowing which it is. The PLC4X Server is a different shape: applications talk to a central PLC4X Server, and that server holds the device connections. That is the topology for multi-machine deployments, where one process owns the sockets and the plant software asks for values.

The in-application utilities are three. The Connection Cache is described as a new implementation of the framework for re-using and sharing PLC connections, which addresses the obvious cost of a driver per request. OPM, Object-Plc-Mapping, binds PLC fields to properties in Java POJOs in a style the README compares to JPA, so a value read from the PLC lands on a typed object field. The Scraper is a utility for scheduled and repeated data collection.

## Where PLC4X fits against the Apache integrations

PLC4X is positioned alongside other Apache projects rather than against proprietary gateways. The README lists Apache Calcite, Apache Camel, Apache Kafka-Connect, Apache Karaf and Apache NiFi as integrations. Each implies a different deployment shape.

The alternative worth naming directly is a vendor SDK plus a bespoke protocol layer. That approach gives you one vendor's full feature set including things PLC4X has no model for, and it gives you the vendor's support contract. What it costs is that every other vendor on the floor is a new dependency, a new error-handling style and a new licence to track. PLC4X inverts that trade: one API surface, a wide protocol set, and the loss of vendor-specific extensions. That inversion is the decision.

For protocol coverage specifically, the repository topics list the families in play: ab, ads, bacnet, can, ethernetip, firmata, knx, modbus, opcua, s7 and siemens. The README excerpt here does not enumerate which of these have a driver in the current release, so treat that list as orientation rather than a feature matrix.

## Reproducibility tooling is treated as a first-class concern

Two shell scripts at the repository root, build-reproducible.sh and compare-reproducible.sh, sit alongside a .dockerignore, a docker-compose.yaml and a Jenkinsfile. That pairing implies a release process that checks whether two builds of the same commit produce the same output, rather than trusting that a passing build was a clean build. For a project that ends up in firmware-adjacent plants, where a driver library version that differs between two sites makes troubleshooting expensive, that is a reasonable investment.

The repository also carries THREAT-MODEL.md, SECURITY.md, an AGENTS.md and DEVELOPMENT.md at the top level. The presence of a threat model document alongside a driver library that opens TCP connections to field equipment says something about how the project treats its threat surface, though the README excerpt does not summarize its contents.

## Release cadence and what 1.0.0 means for adoption

Apache PLC4X 1.0.0 was released on 2026-09-07, alongside a rel/1.0 branch tag the same day. The version before it, 0.13.1, dates from 2025-08-29. So the 1.0.0 line is recent, and the gap between it and the previous tag is about a year of work behind a 0.x version.

That has a practical consequence for anyone pinning dependencies. Between 0.13.1 and 1.0.0 the API had a full major-version cycle to move, so code written against 0.13.x is not a drop-in for the 1.0 line. Plan the migration as an API change rather than a version bump, and check RELEASE_NOTES at the repository root, which is where that work is recorded.

The licence is Apache 2.0. For commercial or redistributed use the obligations are the standard attribution and notice requirements, which the top-level LICENSE and NOTICE files carry, and the project ships a licenses/ directory for the third-party inventory.

## Conclusion

Adopt PLC4X for the Java side of a plant-floor integration when you would otherwise write one driver per vendor and a mapping layer above them, since the connection cache, the OPC-UA Server and the PLC4X Server already cover the plumbing Java applications normally reinvent. Do not adopt it if your only target runtime is Python or .NET: the README marks those bindings as not ready for usage and the .NET one as abandoned. Before choosing it, check the getting-started page for your language against the driver you need, and confirm your build hosts have Java 21, since go.mod is not the constraint but the JDK floor is.

## FAQ

### Which Java version does Apache PLC4X require?

The README states the minimum is Java 21 and that it has been tested up to Java 24. At least Java 21 is also required to build all parts of the plc4x-extras repository.

### Is the Apache PLC4X Python binding ready to use?

Not according to the README, which lists Python as not ready for usage. Java and Go are the shipped languages, and the .NET binding is additionally marked abandoned.

### Why does building a single PLC4X submodule fail?

The code generation needs extra VM settings. A root build applies them from .mvn/jvm.config automatically, but a submodule build requires you to pass the jdk.compiler add-exports flags yourself, for example under IntelliJ's Maven Runner JVM Options.

### Where do the OPC-UA Server and PLC4X Server ship from?

Both are released as part of the plc4x-extras release, not from the core artifacts. The integration modules with Calcite, Camel, Kafka-Connect, Karaf and NiFi ship there as well.

## Sources

- [apache/plc4x on GitHub](https://github.com/apache/plc4x)
- [License: Apache-2.0](https://github.com/apache/plc4x/blob/develop/LICENSE)
- [Project website](https://plc4x.apache.org/)
- [README](https://github.com/apache/plc4x/blob/develop/README.md)
- [Releases](https://github.com/apache/plc4x/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/apache-plc4x
