ergo is a free, open source orchestration & scheduling project written in Go and released under MIT. It has 4,660 GitHub stars, 191 forks and 0 open issues, and was last pushed 11 days ago. On this registry it ranks #32 of 64 tracked projects in Orchestration & Scheduling, with 5 head-to-head comparisons available. It gained 2 stars over the last 3 tracked days.

What is ergo?

What it is

Ergo is an actor-based framework for Go that brings network transparency to event-driven architecture, drawing direct inspiration from Erlang/OTP. It lives in the Go ecosystem and is distributed as a pure-Go library with zero external dependencies. The framework models every unit of work as an isolated process that communicates only through messages, so shared state, mutexes, and race conditions are eliminated by design rather than managed by convention.

The concrete problem Ergo solves is the operational overhead that appears once a Go system outgrows goroutines and channels. As services multiply, developers end up hand-rolling service discovery, retry logic, connection pool management, and cross-node messaging. Ergo replaces that stack with a single model: actors that are addressable across any cluster, supervised automatically, and reachable through the same API whether they run locally or on another continent. Failure recovery is handled by supervision trees that restart failed processes, and distributed pub/sub is built into the framework rather than bolted on.

Key capabilities

  • Actor model with sequential message handling, so a process needs no locks even with thousands of concurrent senders.
  • Network transparency: the same node.Send API works for local and remote actors without code changes.
  • Built-in service discovery, removing the need for an external tool to locate peers across a cluster.
  • Supervision trees that restart failed actors automatically, providing Erlang-style fault tolerance.
  • Distributed pub/sub where a producer registers an event once and any process on any node subscribes, delivering one network message per node rather than per subscriber.
  • Four priority queues per mailbox with guaranteed delivery and no dropped messages.
  • An MCP endpoint served by Observer that exposes a running cluster to MCP-compatible AI assistants such as Claude Code and Cursor.

Who uses it and how

  • Real-time backends where each WebSocket connection becomes an addressable actor, allowing any node in the cluster to push to a specific client without pub/sub intermediaries.
  • IoT platforms running one actor per device, with thousands of devices per node and supervisors that restart failed device actors automatically.
  • Multi-agent AI systems where each agent is an isolated actor with its own mailbox, giving crash isolation, supervision, and distributed addressability.
  • Financial and event-driven systems that rely on the four priority queues per mailbox and guaranteed delivery.
  • Distributed pub/sub deployments where a producer registers an event once and subscribers across the cluster receive it, with delivery cost scaling by node rather than by subscriber count.

Getting started

The README points to documentation at docs.ergo.services and a GitBook, and the framework is installed as a pure-Go dependency with no external packages required. A node is started with ergo.StartNode and actors are spawned from a factory function using node.Spawn.

When to use it — and when not to

Ergo is a strong fit when a Go system has outgrown goroutines and channels and the team wants Erlang-style supervision and distribution without assembling service discovery, retries, and cross-node messaging by hand. The README does not list paid products it replaces, so no direct commercial comparison is available. The evident trade-off is that adopting the actor model means restructuring existing code around isolated processes and message passing, and the framework's own benchmarks are self-reported from make bench rather than independently verified.

project readme (upstream, from github) — read inline

Gitbook Documentation MIT license Telegram Community Reddit

Actor model for Go. Build distributed systems without the distributed systems headache.

Goroutines and channels work great until your system grows. Then come the mutexes, the race conditions, the service discovery configs, the retry logic, the connection pool management. Ergo replaces all of that with one model: isolated processes that communicate through messages, supervised automatically, addressable across any cluster.

Inspired by Erlang/OTP. Zero external dependencies. Pure Go.

The core idea in 30 seconds

type Counter struct {
    act.Actor
    count int
}

type MessageInc struct{}

func (c *Counter) HandleMessage(from gen.PID, msg any) error {
    switch msg.(type) {
    case MessageInc:
        // safe without locks even with thousands of concurrent senders:
        // messages are processed one at a time
        c.count++
        c.Log().Info("count: %d", c.count)
    }
    return nil
}

func factory_Counter() gen.ProcessBehavior { return &Counter{} }

// Start a node and spawn the actor
node, _ := ergo.StartNode("mynode@localhost", gen.NodeOptions{})
pid, _ := node.Spawn(factory_Counter, gen.ProcessOptions{})

// Same API whether local or on another continent
node.Send(pid, MessageInc{})
node.Send(pid, MessageInc{})

No locks. No race conditions. Sequential message handling is the guarantee.

Why not just goroutines + channels?

Goroutines + channels Ergo
Shared state You manage with mutexes No shared state by design
Failure recovery Manual Supervision trees restart automatically
Cross-node messaging Build it yourself Same API, transparent
Service discovery External tool needed Built in
Race conditions Possible Impossible within a process

What you can build

Real-time backends. Each WebSocket connection becomes an addressable actor. Any node in your cluster can push to any specific client. No pub/sub intermediaries.

IoT platforms. One actor per device. Thousands of devices per node. Supervisors restart failed device actors automatically.

Multi-agent AI systems. Each agent is an isolated actor with a mailbox. Crash isolation, supervision, distributed addressability, and an MCP endpoint served by Observer that opens the running cluster to any AI assistant (Claude Code, Cursor, and other MCP-compatible clients). See AI Agents for patterns and diagnostics.

Financial and event-driven systems. Four priority queues per mailbox, guaranteed delivery, no dropped messages.

Distributed Pub/Sub across the cluster. Producer registers an event once; any process on any node subscribes. The framework delivers one network message per node, not per subscriber. 1M subscribers across 10 nodes cost 10 network messages, not 1M.

// Producer on any node
token, _ := producer.RegisterEvent("prices", gen.EventOptions{})
producer.SendEvent("prices", token, PriceUpdate{Asset: "BTC", Price: 95000})

// Subscriber on any other node, identical API
process.MonitorEvent(gen.Event{Name: "prices", Node: "producer@host"})

func (s *Sub) HandleEvent(event gen.MessageEvent) error {
    fmt.Println(event.Message.(PriceUpdate))
    return nil
}

Performance

  • 25M+ messages/second locally
  • ~5.8M messages/second over the network
  • Distributed Pub/Sub: 2.9M msg/sec delivery to 1,000,000 subscribers across 10 nodes

Lock-free queues. Processes sleep when idle. No CPU wasted.

The numbers come from make bench, which measures four scenarios: one process sending to one process, and one pair per CPU, each on a single node and across a connection between two nodes. msg/sec is the rate messages are carried end to end - the send loops included, not the rate Send is called at.

On an AMD Ryzen Threadripper 3970X (32 cores, 64 threads):

$ make bench
go test -run XXX -bench . -benchmem -benchtime 5s ./testing/benchmarks/...
goos: linux
goarch: amd64
pkg: ergo.services/ergo/testing/benchmarks/ping
cpu: QEMU Virtual CPU version 2.5+
BenchmarkLocal11-64        14633359     459.0 ns/op    2178526 msg/sec     58 B/op    2 allocs/op
BenchmarkLocalNN-64       143445265      39.08 ns/op  25591080 msg/sec     69 B/op    2 allocs/op
BenchmarkNetwork11-64       6348997     908.9 ns/op    1100193 msg/sec    776 B/op    6 allocs/op
BenchmarkNetworkNN-64      34500532     172.2 ns/op    5807413 msg/sec    150 B/op    6 allocs/op
PASS

On an Apple M4 Max (14 cores: 10 performance, 4 efficiency):

$ make bench
go test -run XXX -bench . -benchmem -benchtime 5s ./testing/benchmarks/...
goos: darwin
goarch: arm64
pkg: ergo.services/ergo/testing/benchmarks/ping
cpu: Apple M4 Max
BenchmarkLocal11-14        31014296     191.4 ns/op    5224960 msg/sec     58 B/op    2 allocs/op
BenchmarkLocalNN-14       100000000      64.97 ns/op  15390843 msg/sec     72 B/op    2 allocs/op
BenchmarkNetwork11-14      13759047     431.2 ns/op    2319322 msg/sec    262 B/op    6 allocs/op
BenchmarkNetworkNN-14      27716260     193.6 ns/op    5166431 msg/sec    137 B/op    6 allocs/op
PASS

The two machines answer two different questions. A single pair costs 191ns per message on the M4 Max against 459ns on the Threadripper - that is per-core speed. Aggregate throughput goes the other way: 25.6M msg/sec against 15.4M, because there are 64 threads to fill instead of 14. What does not move is the allocation count: 2 allocations per local message and 6 per message that crosses the network, on both machines.

The cpu: line of the Linux run reports the hypervisor's string; the hardware underneath is the Threadripper.

Full benchmarks: benchmarks repository.

Observer

Observer is a real-time web UI for monitoring and inspecting Ergo nodes. It provides live visibility into every layer of the system:

  • Processes - full process list with state, mailbox depth, latency, running time, wakeups, and uptime. Click any process to inspect its supervision tree, links, monitors, aliases, environment, and internal actor state
  • Applications - running applications with their process trees, modes, and uptime
  • Network - cluster topology, per-node connection details, traffic counters, and protocol info
  • Events - registered events with producer, subscriber counts, and publication statistics
  • Logs - live log stream with level filtering across the cluster
  • Profiler - goroutine dump with grouping and stack traces, heap profile with allocation breakdown, and GC pressure charts

Add Observer to your node as an application:

import "ergo.services/application/observer"

options.Applications = []gen.ApplicationBehavior{
    observer.CreateApp(observer.Options{}),
}

To see it in action with a fully loaded cluster, see the observability example. For more information, visit the Observer documentation.

Features

  1. Actor Model: isolated processes communicate through message passing, handling messages sequentially with four priority queues. Supports asynchronous messaging and synchronous request-response, with per-process mailbox latency measurement (-tags=latency) for production diagnostics.

  2. Network Transparency: actors interact the same way whether local or remote. Uses EDF (Ergo Data Format), a custom binary serialization with type caching, pointer support, and message versioning for seamless upgrades. Includes connection pooling, compression, message fragmentation, and application-level keepalive for silent failure detection.

  3. Supervision Trees: hierarchical fault recovery where supervisors monitor child processes

readme truncated — read the full docs on github

Frequently asked questions

Is ergo free to use?

ergo is open source under the MIT licence. There is no licence fee and no seat count — you can self-host it or, where the project offers one, pay a vendor for a managed version instead.

What does ergo do?

An actor-based Framework with network transparency for creating event-driven architecture in Golang. Inspired by Erlang. Zero dependencies.

What is ergo written in?

ergo is primarily written in Go. Its source is publicly available at https://github.com/ergo-services/ergo, and it has 4,660 GitHub stars.