open62541: an OPC UA stack in C for embedded and industrial servers
Open source implementation of OPC UA (OPC Unified Architecture) aka IEC 62541 licensed under Mozilla Public License v2.0
At a glance
- What is it?
- open62541 implements OPC UA (IEC 62541) in C99 under MPLv2, with a single-file distribution for embedding. It suits engineers who need a client or server inside an existing C application, not a turnkey SCADA product.
- Who is it for?
- Adopt open62541 if you are writing a C or C++ application that must speak OPC UA natively, especially on an embedded target where a single amalgamated open62541.c/.h pair is easier to integrate than a runtime. Do not adopt it if you want a graphical OPC UA server you configure rather than compile, or if your team has no C build chain.
- Can I use it commercially?
- Yes, with conditions. MPL-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 received new commits within the last day.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What open62541 solves for industrial C codebases
OPC UA is a large specification: address space, services, session handling, security policies, encodings. Writing that from the wire format up is months of work that has nothing to do with the machine you are trying to expose. open62541 provides the protocol layer so that a C application can publish its data as an OPC UA server or consume another server as a client. The README describes it as "an open source implementation of OPC UA (OPC Unified Architecture / IEC 62541) written in the C language", usable "to implement dedicated OPC UA clients and servers, or to integrate OPC UA-based communication into existing applications". That second clause is the real target: existing applications. The library is aimed at people who already have a C codebase, a PLC firmware, a gateway daemon, or a test rig, and need OPC UA as one more interface rather than as the whole product.
The topics list on the repository points at the same audience: industrial automation, publish-subscribe, TSN, embedded. The core library has no dependencies beyond C99 standard headers, which is the constraint that makes embedded use plausible at all. Everything platform-specific is pushed into an EventLoop plugin, so the core does not link against POSIX sockets directly. If you are building for an RTOS or a microcontroller, that plugin boundary is where your porting effort goes.
How the stack is layered and where the code lives
The repository layout separates four concerns. The public API sits in /include, with plugin headers under /plugins/include. The core library in /src implements the OPC UA services and depends only on C99 headers. Architecture support lives in /arch and is reached through the EventLoop plugin, which keeps POSIX calls out of the core. Default plugin implementations in /plugins cover crypto primitives and storage of the information model, so you can swap mbedTLS for OpenSSL, or a different information-model backend, without touching the service layer. Third-party code is vendored under /deps via git submodules or internalized directly, with licenses listed in deps/README.md.
Some of the source is generated rather than written. The README states that code is auto-generated from XML definitions that are part of the OPC UA standard, and that the generation scripts use Python as part of the build process. In practice this means a Python interpreter is part of your build environment even though it is not part of the runtime. It also means the information model types you get are tied to the standard XML you configure, not to hand-written C.
The most consequential structural decision for integrators is the amalgamation. The README says the sources "can be compressed (amalgamated) into a single-file-distribution, a pair of open62541.c/.h files", and that the functionality included in that distribution depends on the current CMake configuration. That last sentence deserves attention: the single file is not a fixed artifact. Turn off a plugin in CMake and the amalgamated file silently lacks it. Teams that vendor open62541.c/.h into a repository should record the CMake configuration that produced it, or the next regeneration will produce a different library.
Installing open62541 and running a first server
The project builds with CMake; the README points to the build documentation at open62541.org/doc/master/building.html for details. A minimal out-of-tree configure and build looks like this. The generator you pass to -G depends on your platform, and the build directory should be empty before you start.
git clone https://github.com/open62541/open62541.git
cd open62541
mkdir build && cd build
cmake -DBUILD_EXAMPLES=ON ..
make -jWith BUILD_EXAMPLES enabled, the examples/ directory is compiled alongside the library. The README says example server and client implementations can be found in /examples, and the repository listing shows a flat set of single-file programs there: client.c, client_connect.c, client_subscription_loop.c, and under examples/pubsub/ and examples/events/ the more specialised ones. After the build, an example server binary is produced in the build tree; running it starts an OPC UA server on the default endpoint, and the matching client example connects to it. The exact binary names come from the CMake targets in examples/CMakeLists.txt, so check that file rather than guessing.
For embedding, the alternative to linking the built library is the amalgamated pair. Configure CMake with the plugins you need, then take the generated open62541.c and open62541.h and add them to your own project. Because the README ties the contents of that pair to the CMake configuration, the practical workflow is: decide the feature set first, generate once, and treat the resulting pair as a build artifact you can reproduce. Do not hand-edit it.
Encryption is not in the bare build. The README states that depending on the build configuration open62541 depends on additional libraries such as mbedTLS or OpenSSL for encryption, so a server that needs secure endpoints requires enabling those at configure time.
Where open62541 is the wrong choice
The library gives you an API, not an application. There is no configuration file that turns a running process into a finished OPC UA server with a browsable address space; you write the C that populates nodes and callbacks. If your requirement is to expose a few tags from an existing PLC and you have no C developers, a packaged OPC UA server product will get you there faster, and open62541 will not.
The dependency story is also narrower than the README's "platform independent" phrasing suggests. Platform independence is achieved through exchangeable plugins, which means somebody has to write or find the plugin for your target. The repository ships ports to different architectures, but a bare-metal target without an existing EventLoop implementation is porting work, not configuration. The topics list mentions ESP32 and the search data shows people looking for STM32 builds, which is consistent with the library being used on microcontrollers, but the README does not promise that any particular MCU works out of the box. Check /arch for your platform before you plan around it.
Build-time complexity is a real cost. CMake plus Python code generation plus optional crypto backends is a heavier toolchain than a typical embedded project, and the amalgamated single file only hides that cost, it does not remove it, because you still need the full build to generate the file. Finally, the README does not document rollback or downgrade procedures between releases, so if you depend on a specific version, pin it explicitly rather than tracking master.
open62541 compared with freeopcua and other OPC UA stacks
The obvious comparison in the search data is open62541 versus freeopcua. Both implement OPC UA and both are open source, but they are written in different languages and that difference drives almost everything else. open62541 is C, with a core that depends only on C99 headers and an EventLoop plugin boundary for architecture-specific code. That design is what makes it embeddable on targets where a C++ runtime or a managed runtime is not available. freeopcua is a C++ project, so it fits naturally into C++ applications and brings the C++ standard library with it. If your codebase is C++, freeopcua may integrate more cleanly; if you are writing firmware or a C daemon, open62541's C99 core and plugin split are the reason to prefer it.
The second axis is distribution shape. open62541 offers the amalgamated open62541.c/.h pair, which the README explicitly frames as a way "to simplify the integration with existing software projects". That is unusual among OPC UA stacks and is the feature that makes vendoring practical when you cannot add a build dependency. If you are evaluating alternatives, ask each one how it is embedded, not just what language it is written in.
Licensing differs in ways that matter for commercial products. open62541 is MPLv2, and the README states that this allows the library to be combined and distributed with proprietary software, with only changes to the open62541 library itself needing to stay under MPLv2. Some plugins and examples are CC0, which the README says can be reused under any license with no publication obligation. Read the actual LICENSE and LICENSE-CC0 files before relying on that distinction; the split between MPLv2 and CC0 files is not uniform across the tree.
Maintenance, releases and the cost of upgrading
The repository is not archived, and the last push was on 2026-09-23, one day before this writing, so the project is under current development. Three release lines were published on 2026-09-06: v1.5.8, v1.4.20 and v1.3.21. That pattern, three maintained branches receiving patch releases on the same day, is the single most useful maintenance fact here. It means you can stay on an older minor line and still receive fixes, which matters for industrial deployments where requalifying a new minor version is expensive.
It also means you have to choose a line deliberately. The README notes that an example server built with open62541 v1.4 was certified for the 'Standard Server 2017 Profile' by the OPC Foundation. If certification of your own product is on the roadmap, that is a reason to look hard at the v1.4 line rather than jumping to v1.5, and to check the certification page for what exactly was certified. The README is explicit that this is an example server, not the library as a whole, so do not read it as a blanket certification.
Upgrade cost concentrates in three places. The public API headers in /include are what your code compiles against. The generated code from the standard XML definitions changes when the specification or the generator changes. The amalgamated file must be regenerated from the new source with your CMake configuration. None of these are documented as having a stability guarantee in the README, so treat a minor-version bump as a rebuild-and-retest event, not a drop-in replacement. CHANGES.md in the repository root is the place to look for what moved between releases.
On governance: the README states that o6 Automation GmbH employs the core contributors and offers commercial support, while contributors retain their individual copyright, which the README says prevents future relicensing. For a project you intend to ship in a product, that is a more concrete commitment than a generic open-source promise.
Editorial conclusion
Adopt open62541 if you are writing a C or C++ application that must speak OPC UA natively, especially on an embedded target where a single amalgamated open62541.c/.h pair is easier to integrate than a runtime. Do not adopt it if you want a graphical OPC UA server you configure rather than compile, or if your team has no C build chain. Before committing, verify three things: that the CMake configuration enables the plugins you need (encryption via mbedTLS or OpenSSL, and the storage backend for your information model), that the single-file distribution produced by your configuration still contains the features you rely on, and that your target architecture has an EventLoop plugin available, since the POSIX port will not build for a bare-metal target. The certification claim in the README applies to an example server built with v1.4, not to your build.
Frequently asked questions
How do I install open62541?
The build environment is generated via CMake, and the README links to the build documentation at open62541.org/doc/master/building.html. A typical sequence is to clone the repository, create a build directory, run cmake with the options you need (for example -DBUILD_EXAMPLES=ON), then run make. For embedding, the sources can also be amalgamated into a single open62541.c/.h pair whose contents depend on the CMake configuration.
Is there a free OPC UA client available that I can build with open62541?
open62541 itself provides the tools to implement OPC UA clients as well as servers, and the repository ships client examples such as examples/client.c, examples/client_connect.c and examples/client_subscription_loop.c. Enabling BUILD_EXAMPLES at configure time builds them alongside the library. The library is licensed under MPLv2, so it can be used without a commercial licence.
How do I connect to an OPC UA server with open62541?
The examples directory contains client programs that establish a connection, including client_connect.c and client_connect_loop.c, plus subscription variants for receiving data changes. The README points to /examples as the place to find example client implementations. The exact endpoint and session setup is handled in those files rather than documented in the README.
What is OPC used for in open62541?
open62541 implements OPC UA, the OPC Unified Architecture also known as IEC 62541, and the README lists its use for dedicated OPC UA clients and servers or for integrating OPC UA-based communication into existing applications. The repository topics place it in industrial automation, publish-subscribe and TSN settings. The library is written in C and targets platform-independent deployment through plugins.
How does open62541 compare with freeopcua?
open62541 is written in C, with a core that depends only on C99 standard headers and architecture-specific code moved into an EventLoop plugin, and it offers an amalgamated open62541.c/.h distribution. freeopcua is a C++ project, so it fits C++ codebases and carries the C++ standard library with it. The README does not discuss freeopcua, so any further comparison has to come from the two projects' own documentation.
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/open62541-open62541)