Elixir and the BEAM for AI systems

Cisco's Network Config Engine Is Secretly Erlang

Cisco NSO and ConfD run their core on Erlang. Why the network-automation world never noticed, and where the BEAM actually fits this domain.

TL;DR: A reader working at a network automation company asked me why there’s no serious open-source Elixir or Erlang tooling for spine/leaf monitoring and config push — everything in that space is Python. The honest answer isn’t “there’s a gap,” it’s “you’re looking in the wrong place.” Cisco’s Network Services Orchestrator — the config engine telcos reach for when they need transactional config push across thousands of devices — runs its core inside an Erlang VM. It came from Tail-f Systems, a company founded by people who built the original Erlang runtime at Ericsson. Nobody markets it that way, so nobody in the Python-dominated network-automation world knows it’s there. Open source went Python for sociological reasons, not technical ones — and this domain is the one Erlang was designed for.

The question

A reader at a network automation company asked me a version of this: why is there no real open-source Elixir or Erlang tooling for spine/leaf network monitoring and automation? Every project that shows up when you search — Netmiko, NAPALM, Nornir, Ansible modules — is Python. If the BEAM is supposedly this good at concurrent, fault-tolerant, long-lived-connection workloads, where’s the network automation story?

The question assumes the answer is “it doesn’t exist.” It exists. It’s just not open source, and nobody who sells it talks about what it’s built on.

The reveal: it already runs on the BEAM

Cisco’s Network Services Orchestrator (NSO) is the tool telcos and large enterprises reach for when they need to push, validate, and roll back configuration across thousands of heterogeneous devices with a transactional guarantee. NSO’s daemon runs inside an Erlang VM — Cisco’s developer documentation carries an entire guide on running your own Erlang applications embedded inside NSO’s VM, with the Erlang API shipped as an OTP application (econfd) for exactly that purpose — Cisco DevNet, Embedded Erlang applications.

NSO didn’t start life at Cisco. It’s the evolution of a product called NCS, built by Tail-f Systems, a Stockholm company Cisco acquired in July 2014 for roughly $175 million — Cisco’s own acquisition announcement and completion notice both confirm the deal and timing. Tail-f’s other flagship product, ConfD (the toolkit embedded directly on network devices to provide NETCONF, CLI, and web management interfaces), exposes C, Java, and Python bindings on top of a daemon that every language binding reaches the same way — over a socket-based IPC interface, with the protocol “almost the same” whether you come in through econfd (the Erlang API, shipped as an OTP application) or libconfd.so (the C API) — Cisco DevNet, NSO Erlang API overview.

Tail-f wasn’t a company that happened to pick Erlang. Its founders came directly out of the team that built the original Erlang runtime at Ericsson. Claes Wikström, one of Tail-f’s co-founders, worked in Ericsson’s Computer Science Lab starting in 1990 on the first Erlang implementation — the garbage collector, distributed Erlang, ets/dets, the driver architecture — before founding a string of Erlang-based startups that culminated in Tail-f — Erlang Factory speaker bio, Erlang User Conference 2013. This isn’t a company that discovered Erlang was useful for their problem after the fact. It’s a company founded by the people who knew, from the inside, exactly what the runtime was built to do — and pointed it at network config management on purpose.

Why doesn’t anyone know this?

There’s no conspiracy — Cisco simply doesn’t sell runtimes, it sells outcomes: “zero-touch provisioning,” “intent-based networking,” “service orchestration.” The DevNet docs that mention Erlang are implementation detail for the small subset of NSO customers writing embedded extensions, not front-page positioning. Nobody writing an NSO sales deck in the last decade had a reason to say “and by the way, this runs on the same virtual machine that runs Ericsson’s phone switches,” because the buyer doesn’t care and the fact doesn’t move a deal.

The result is a strange asymmetry: the most operationally serious config-push engine most network engineers will ever touch is quietly running an Erlang VM at telco scale, and almost nobody who uses it knows it, because the entire go-to-market apparatus around it was built to talk about YANG models and service templates, never about the runtime underneath.

Why open source went Python instead

If you’re looking for open-source tooling, you land in Netmiko, NAPALM, Nornir, and Ansible network modules — all Python, and that’s not a coincidence of technical superiority, it’s sociology. Python is the scripting entry point most network engineers already have, and Netmiko was built for that audience — it met them where they were. Ansible had the DevOps-tooling gravity well already pulling every kind of infrastructure automation toward it. NAPALM and Nornir grew up in that same ecosystem because the people writing network automation tooling in the 2015–2020 window were, overwhelmingly, Python-fluent network engineers extending what they already knew, not systems engineers evaluating BEAM versus CPython on connection-handling characteristics. Open source tooling follows the community that writes it, and the community that writes network automation tooling learned Python — a straightforward instance of the same dynamic I’ve written about elsewhere: the BEAM’s fit for AI agent workloads is technically strong and still loses mindshare to whatever the incoming cohort already knows.

None of that is a knock on those tools. Netmiko and NAPALM are good at what they do, and for a shop where everyone already reads Python, they’re the correct default. The point is narrower: “nobody built it in Erlang” was never true. Nobody built the open-source, community version in Erlang. The commercial, closed-source, extremely well-funded version has been running in production at telco scale for over a decade.

Why the BEAM actually fits this domain

Set the sociology aside and look at the shape of the problem, because it maps onto what Erlang was built for with unusual precision. Erlang was designed at Ericsson specifically for telecom switching software — the AXD301 ATM switch, first delivered in 1998, carried over a million lines of Erlang code and was, in Joe Armstrong’s words, “thought to be one of the most reliable products ever made by Ericsson” — built around the premise that a switch has to keep running while individual components fail around it — Joe Armstrong’s 2003 thesis. The often-repeated “nine nines” availability figure attached to AXD301 gets argued over every time it surfaces (this Hacker News thread is a representative round), and I won’t assert it as fact. What’s not in dispute is the design intent: Erlang exists because a switch cannot go down, and the runtime’s supervision trees, lightweight process model, and let-it-crash philosophy were built directly against that requirement.

Network config automation at spine/leaf scale has the same shape as a telecom switch, structurally:

  • Tens of thousands of long-lived sessions. SSH, NETCONF, and gNMI connections held open per device is exactly the profile the BEAM’s concurrency model was built for — cheap, isolated, million-process-capable.
  • Flaky hardware, expected failure. A device that drops a session mid-push, times out, or returns malformed output isn’t an edge case in this domain, it’s Tuesday. Supervision trees that restart a failed worker in isolation without taking down the fleet-wide job map directly onto “one switch misbehaving shouldn’t kill the orchestration run.”
  • Config push is a state machine. Idle, pushing, verifying, committed, rolled back — that’s gen_statem with the serial numbers filed off. Every network automation tool ends up hand-rolling some version of this state tracking in Python because the language doesn’t give you a supervised state-machine primitive; Erlang ships one in the standard library.

That third bullet in code — the skeleton every Python tool hand-rolls, straight from the standard library:

-module(config_push).
-behaviour(gen_statem).
-export([callback_mode/0]).
-export([idle/3, pushing/3, verifying/3]).

callback_mode() -> state_functions.

idle({call, From}, {push, Config}, Data) ->
    {next_state, pushing,
     Data#{config => Config},
     [{reply, From, ok}]}.

pushing(info, {device_ack, ok}, Data) ->
    {next_state, verifying, Data};
pushing(info, {device_ack, {error, _}}, Data) ->
    {next_state, rolling_back, Data}.

verifying(info, {verified, true}, Data) ->
    {next_state, committed, Data};
verifying(info, {verified, false}, Data) ->
    {next_state, rolling_back, Data}.

Each state is a function, and the runtime supervises the process holding it. When the push worker for one switch dies mid-verify, its supervisor restarts it and the other few thousand workers never notice.

Tail-f’s founders didn’t need a case study to see this. They’d built the runtime that solved the same problem for phone switches and pointed it at the next domain that looked the same.

What to actually do with this

This is where I’d stop most people before they get excited: this is not a pitch to rewrite your network automation platform in Elixir. If your team is a Python shop and nobody on it knows OTP, walking in with “we should replace Nornir with a BEAM platform” is a bus-factor problem you’re creating on purpose, not solving. I’ve watched technical leads pitch a stack swap because the underlying tech is genuinely better and lose months to the fact that “better” doesn’t matter if the only person who can debug it is the one who pitched it.

What this is good for is a bounded side tool where the BEAM’s properties are the whole point and the blast radius of “only one person understands it” is small: a config-drift monitor watching a fleet for divergence from intended state, a connection-health dashboard tracking session state across thousands of devices in real time, a narrow orchestration worker that supervises retries on a flaky push path Ansible currently handles with brittle retry loops. Scoped that way, you get the concurrency and supervision properties where they matter, without asking a Python-fluent team to adopt a runtime they’ll resent maintaining. That’s also the honest test for whether this is worth building at all: if you can’t name the specific tool and the specific person maintaining it, it’s an essay, not a project.

This is a genuinely underserved niche — a serious commercial product has been quietly proving the technical fit for over a decade, and the open-source layer never caught up because the people writing that layer never had a reason to look. Next time someone tells you there’s no fault-tolerant runtime built for their problem, check what’s actually running under the vendor tool they already pay for first. And if you’re weighing whether a bounded BEAM tool belongs on your team’s roadmap, that’s a conversation worth having before it becomes a commitment, not after.