# The best open source EtherCAT libraries, and what to use when

> Four open source EtherCAT master stacks, one honest comparison. The most mature one is IgH EtherLab and we could not ship it, for reasons that have nothing to do with the code. Here is the question that decides your stack before you write a line, and the class of device that quietly comes up empty.

Author: Milorad Srdic. Published: 2026-09-24. Updated: 2026-09-26.
Canonical URL: https://www.mutexer.com/blog/ethercat-open-source-libraries
Source: mutexer (https://www.mutexer.com)

---

You have picked EtherCAT. The hardware is on the bench, the coupler is blinking
at you, and now you have to choose a master stack.

So you search. You'll quickly get four names that stand out. However, all four
are very different and for different reasons.

We went through this properly last year, for a product that puts a coding agent
on the industrial PC itself. Here is what we found, including the part where the
best library lost.

## Short answer

| Your situation | Use |
|---|---|
| You control the machine, the kernel and the build | IgH EtherLab |
| You are already a C shop and want something small | SOEM |
| You ship a single binary onto hardware you do not control | ethercrab |
| You cross-compile to musl or Arm and want no C in the tree | ethercrab |
| You need FoE firmware transfer, EoE, or cable redundancy | IgH EtherLab |
| Your chain includes a modular coupler with backplane IO | IgH, or ethercrab with the module configuration written by hand |

The rest of this is why.

## The four EtherCAT master libraries worth knowing

**[IgH EtherLab](https://gitlab.com/etherlab.org/ethercat).** C, roughly twenty years old, and the most capable of the four
by a wide margin. CoE, EoE, FoE and VoE mailboxes. Native EtherCAT NIC drivers
plus a generic one. RTAI, Xenomai and PREEMPT_RT support. EEPROM and SII
tooling. It claims IEC/PAS 62407 conformance and it has a long field record
behind it. If you are reading a list like this hoping someone will just tell you
which one is best, it is this one.

**[SOEM](https://github.com/OpenEtherCATsociety/SOEM).** Also C, much smaller, BSD-like licence with a linking exception. Easy
to read, widely deployed, and a perfectly reasonable default if you are already
a C shop.

**[ethercrab](https://github.com/ethercrab-rs/ethercrab).** Pure Rust, MIT or Apache-2.0, `std` and `no_std`. The youngest of
the four by a long way. It is what we shipped.

**The `ethercat` crate.** Rust bindings onto IgH. It inherits everything IgH
gives you, and everything IgH costs you.

There is also acontis EC-Master, which is commercial and therefore a different
conversation. We did not evaluate it.

## How you ship decides your EtherCAT library

Not "which is best". **"How are you shipping this?"** The answer changes
completely across three cases.

**You control the whole machine,** including the kernel and the build. IgH is
excellent, the licence is a non-issue, and you should take the mature stack.
Genuinely, stop reading and go and use it.

**You are shipping a binary onto someone else's hardware.** IgH wants an
out-of-tree kernel module. A single file you copy onto a controller can't carry
one, and an update pipeline that replaces a binary can't install one. That is
what ended it for us.

The licence is a second and smaller question, and it's worth being precise
because it gets repeated wrongly. `libethercat` is LGPL 2.1, and LGPL 2.1 does
allow static linking.
[IgH's own 1.5 manual](https://docs.etherlab.org/ethercat/1.5/pdf/ethercat_doc.pdf)
says the library is licensed that way specifically to permit it, and ships
`libethercat.a` for the purpose. The
[1.6 manual](https://docs.etherlab.org/ethercat/1.6/pdf/ethercat_doc.pdf)
changes that sentence to dynamic linking. Either way the obligation is
the same one LGPL always carries: whoever you give the binary to has to be able
to relink it against their own build of the library. That is a real thing to
take on for a single distributed file. It is not the blocker people assume.

**You are cross-compiling to musl, or to Arm, or both.** A C dependency turns
your build into a cross-compilation project. That cost is not paid once. It is
paid every release, by whoever is on call.

We are the second and third cases at the same time. That single distribution
decision knocked out IgH, knocked out the crate that binds to IgH, and knocked
out SOEM's bindgen path. What was left that could still do CoE was ethercrab.

None of that is a quality judgement. We rejected the best library in the list
on packaging grounds. If your packaging is different, you should reach a
different answer.

## What we found using ethercrab

Everything below was checked against ethercrab 0.7.1, the current release as of
September 2026, by reading the crate source rather than the documentation.

**It gives you the wire, not the device.** ethercrab is a master implementation.
It does not read ESI at all. So a product code comes back as `0x044c2c52` and
stays that way. You need the vendor's ESI file to get a name out of it.

We wrote our own ESI reader for four fields: vendor id, vendor name, product
code and device name. There is a full ESI parser on crates.io. We did not take
it. We needed four fields and it models the entire specification.

**Its automatic configuration only ever reads.** ethercrab discovers the PDO mapping a device is already reporting and builds the
process image from that. It does not write a mapping. There is not a single SDO
write in its configuration path.

For a simple terminal that describes itself in EEPROM, this is fine and you will
never notice.

### Why ethercrab could not map our modular coupler

For a modular coupler it is not fine. Some couplers have no fixed process image:
the IO sits on a vendor backplane bus behind the EtherCAT node, and what the
device exposes depends on which modules are fitted. EtherCAT has a mechanism for
this. The master writes a Configured Module Ident List at object
[`0xF030`](https://infosys.beckhoff.com/content/1033/ax8xxx_object/11594018059.html)
to tell the coupler what is behind it, then assigns the PDOs explicitly. Until that
happens, the modules are not selected and their IO is not in the process image.

ethercrab has no concept of modules. Search the 0.7.1 source for that object,
for `0xF050`, or for the words "module ident", and you get nothing.

So it comes up clean. The device enumerates. It reaches PRE-OP. Nothing errors.
The process image is built correctly out of what an unconfigured coupler
reports, which is not the IO you wanted. Everything is green and the backplane
is not there.

Here is the bit that got me. ethercrab **parses the ESI flags that mark
exactly this case.** There are flags for a PDO that comes from a
module, that depends on a slot, that is overwritten by a module. They are all
defined, all named after their ESI attributes, and then the flags field is
commented out of the struct and nothing reads it. The library has the full
vocabulary for modular devices and no implementation behind it.

It is not a dead end, and it is not something EtherCAT makes impossible. IgH does it. The vendor tools do it. SDO writes are public in ethercrab, and upstream's answer to configurable
mapping is to write the assignment by hand in the PRE-OP hook. Their front page
shows you how. You can drive a modular coupler with it. You just
have to write the module configuration yourself, and nothing will tell you that
is the piece you are missing.

**And it is young, and its changelog says so.** Version 0.7.0, released in
March 2026, fixed reading a
device's status code from the correct register when a state transition fails,
and returning the real CoE abort code instead of a generic one. Those are bugs a
twenty-year-old stack fixed a long time ago. That is what adopting a pre-1.0
library looks like, and you should see it before you commit. As of 0.7.1 it also implements CoE only,
so no firmware transfer over FoE and no tunnelled Ethernet over EoE, and it has
no cable redundancy. If you need any of those, go back to IgH.

## Starting an EtherCAT master resets the segment

On EtherCAT there is no such thing as a harmless read. Bringing up a master
broadcasts every device on the segment back to INIT, blanks all sixteen FMMUs
and all sixteen sync managers, blanks the distributed clock configuration, and
overwrites every configured station address. On a running machine that is not a
read. That is a stop, and it discards the plant master's configuration on the
way out.

That is not a quirk of any one implementation. It is what EtherCAT is: one
master per segment, the master owns the wire, and there is no client seat to sit
in. Modbus and OPC UA let you dial a device that is already serving other people
and ask it a polite question. EtherCAT has no equivalent, and anyone carrying
Modbus intuition across will eventually stop a line with something they thought
was a read.

It is why our EtherCAT tools are split in two. Broadcast and auto-increment
register reads, which change nothing, are the ordinary path. Anything that takes
the bus is compiled out by default and sits behind a permission tier that cannot
be waived.

The limitation people test first, so here it is up front: those tools observe
a segment. Your application is still the master.

## So, what did you pick

If you are shipping a machine you own end to end, take IgH and do not
overthink it. If you are shipping software onto hardware you do not control, the
kernel module and the licence will decide it for you before the feature tables
get a vote.

Oasis CLI is free, runs on the machine rather than your laptop, and works with
your own local models. It is at [/oasis-cli](/oasis-cli) if you want a look.
