Distributed actor framework for Go

GoAkt: the actor model for Go

Locks, channels, and a broker are three ways to coordinate state. An actor is one.

GoAkt is a distributed actor framework for Go. Typed messages, supervision, clustering, and Grains behind one API, from a single process to a cluster of nodes.

go get github.com/tochemey/goakt/v4

In production at Baki Money and on a 31-pod analytics platform. Read the production report ↓

By the numbers

One actor, one sender
13.2Mmsg/s
Eight actor pairs in parallel
27.2Mmsg/s
Per actor, one million live
1.23KB
Per grain, one million live
609B
Run details and method

Actors in action

Tell and Ask are the same call on every edge.

Actors keep their state private and talk only through messages. Tell sends and moves on. Ask sends and waits for the reply. The call stays the same whether the receiver runs in this process or on another node, which the docs call location transparency.

Three GoAkt nodes exchanging messages over every edge node-1 node-2 node-3
Tell / Ask, same API on every edge

Your first actor

One struct, one Receive method, one message at a time.

This is the whole program from the quickstart. Nothing is elided.

main.go
package main

import (
    "context"
    "os"
    "os/signal"
    "syscall"
    "time"

    goakt "github.com/tochemey/goakt/v4/actor"
    "github.com/tochemey/goakt/v4/log"
)

// Greet asks the actor to greet someone; Greeting is its reply.
type Greet struct{ Name string }

type Greeting struct{ Message string }

// Greeter is the actor. State lives in unexported fields; no locks are
// needed because an actor processes one message at a time.
type Greeter struct {
    greeted int
}

var _ goakt.Actor = (*Greeter)(nil)

func (x *Greeter) PreStart(*goakt.Context) error { return nil }

func (x *Greeter) Receive(ctx *goakt.ReceiveContext) {
    switch msg := ctx.Message().(type) {
    case *Greet:
        x.greeted++
        ctx.Response(&Greeting{Message: "Hello, " + msg.Name + "!"})
    default:
        ctx.Unhandled()
    }
}

func (x *Greeter) PostStop(*goakt.Context) error { return nil }

func main() {
    ctx := context.Background()
    logger := log.DefaultLogger

    system, err := goakt.NewActorSystem("quickstart", goakt.WithLogger(logger))
    if err != nil {
        logger.Fatal(err)
    }

    if err := system.Start(ctx); err != nil {
        logger.Fatal(err)
    }

    pid, err := system.Spawn(ctx, "greeter", &Greeter{})
    if err != nil {
        logger.Fatal(err)
    }

    response, err := goakt.Ask(ctx, pid, &Greet{Name: "World"}, time.Second)
    if err != nil {
        logger.Fatal(err)
    }

    logger.Info(response.(*Greeting).Message)

    sig := make(chan os.Signal, 1)
    signal.Notify(sig, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
    <-sig

    _ = system.Stop(ctx)
}

Why actors

Four things you stop writing yourself.

Simpler concurrency

Actors process one message at a time. You write plain Go with no locks, channel plumbing, or shared-state bugs.

Location transparency

Send a message to a local, remote, or clustered actor with the same API. The framework handles the wire.

Resilience by design

Supervision trees and the let-it-crash model keep failures contained and recoverable.

Batteries included

Clustering, Grains, CRDTs, streams, scheduling, passivation, and observability, without re-rolling them yourself.

In production

31 pods, one monolith, and no broker in between.

A self-hosted analytics platform runs as one Go monolith on Kubernetes at about 31 pods. GoAkt is the entire distribution layer: no message broker, no service mesh, and no external actor registry.

In their words

The headline is that the actor core has not been a source of surprises. Message passing, supervision, placement, and grain single activation behave exactly as documented under steady state, and none of our production incidents in this stack originated there.

StringKe, production report on a self-hosted analytics platform, July 2026
Inbound connections
Each WebSocket or SSE connection is an actor with a cluster-wide name, so delivering to a user is a Tell instead of a Redis lookup.
Outbound integrations
One grain per third-party connection, activated exactly once across the cluster.
Reporting
Aggregations run as map and reduce over messages, with mailbox back-pressure.
Scheduled work
Cluster single-fire cron lets the external scheduler retire.

Also in production

  • Baki MoneyAI-powered expense tracking that turns receipts into stories. Actors cache the app's data today, with wider use planned.

Being built on GoAkt

  • V-App IoT BuilderClustered complex event processor. Users draw the rules applied to incoming sensor data.
  • GalaxyDistributed real-time game platform. Clustered actors and grains hold player state, matchmaking lobbies, and game sessions.

Running GoAkt in production? Write a short report to be listed here, or leave a note in the feedback thread.

Where it fits

Systems that are concurrent, stateful, and expected to survive failure.

Each workload below names the features that carry it, so you can judge the fit before writing code.

Distributed systems and microservices

Stateful microservices · Long-lived processes · Service-to-service messaging · Event-driven architectures
  • Stateful microservices: keep state next to the compute with actors or grains and scale horizontally across a cluster, instead of round-tripping to a cache on every request.
  • Long-lived processes: model workflows that outlive a single request; supervision restarts failed actors and relocation moves them when a node leaves the cluster.
  • Service-to-service messaging: exchange typed messages asynchronously with location transparency; the caller does not care which process or node handles them.
  • Event-driven architectures: build event sourcing and CQRS on eGo, which uses GoAkt for execution, supervision, clustering, and remoting.

Real-time systems

Financial market data · Gaming servers · IoT and edge computing · Chat and presence
  • Financial market data: fan price updates, risk checks, and order flow across routers with per-instrument actors serializing access to hot state.
  • Gaming servers: give each player session its own actor or grain; passivation reclaims memory when sessions go idle.
  • IoT and edge computing: represent each device as a digital twin grain, activated on first message and addressable from anywhere in the cluster.
  • Chat and presence: distribute conversations and notifications over PubSub topics that work the same in standalone and cluster mode.

High-performance data processing

Stream processing · ETL pipelines · Event-driven analytics
  • Stream processing: run fraud detection, anomaly tracking, and alerting pipelines on streams backed by actor concurrency.
  • ETL pipelines: spread batch workloads across worker actors with work pulling, so fast workers take more of the load and slow ones are never overwhelmed.
  • Event-driven analytics: subscribe actors to live event streams and compute on demand as events arrive.

Fault-tolerant systems

Self-healing applications · High availability · Replicated state
  • Self-healing applications: supervision trees restart failing components with directives, restart budgets, and exponential backoff, while the rest of the system keeps serving.
  • High availability: a cluster redistributes actors from a lost node to healthy peers through relocation, without an operator in the loop.
  • Replicated state: share counters, sets, and maps across nodes with conflict-free distributed data types that converge without coordination.

Workflow orchestration and automation

Business processes · Background jobs · Workflow engines
  • Business processes: automate approval chains, payments, and order fulfilment as actors that hold each case's state; eGo adds saga orchestration when steps span services.
  • Background jobs: the built-in scheduler delivers a message once after a delay, on an interval, or on a cron expression, to a local or remote actor, with pause, resume, and cancel by reference. In a cluster, a cron schedule registered on every node fires once per tick.
  • Workflow engines: model multi-step processes with behaviors that switch the message handler as the process advances, and stashing to defer messages that arrive too early.

Security and threat detection

Intrusion detection · Bot and DDoS mitigation · Transaction validation
  • Intrusion detection: process log and telemetry streams in real time, one actor per source, and escalate suspicious activity through the actor hierarchy.
  • Bot and DDoS mitigation: throttle abusive traffic with per-client actors that count, rate-limit, and expire through passivation.
  • Transaction validation: run validation and consensus steps as isolated actors so one poisoned input cannot corrupt shared state.

AI and machine learning

Distributed training coordination · Real-time inference serving · Multi-agent systems
  • Distributed training coordination: coordinate workers across a cluster with actor-based scheduling and reliable point-to-point delivery.
  • Real-time inference serving: pool model workers behind routers and keep tail latency down with one request in flight per worker.
  • Multi-agent systems: give every agent an actor with private state, a mailbox, and supervision; agents collaborate by exchanging typed messages.

AI agents and MCP servers

Agent coordination · Tool orchestration · Conversation management · Agent swarms · Resilient pipelines

Actors map naturally onto agent runtimes: an agent is a unit of state, memory, and autonomy that talks to peers through messages. The AI agents guide makes the case feature by feature.

  • Agent coordination: spawn one actor per agent and let the actor hierarchy express delegation and oversight.
  • Tool orchestration: manage concurrent MCP tools, databases, APIs, and knowledge sources as child actors, each supervised independently.
  • Conversation management: hold each conversation in a grain that activates on the first message and passivates when the user goes quiet.
  • Agent swarms: distribute reasoning across a cluster where agents delegate tasks to peers with location-transparent messaging.
  • Resilient pipelines: supervision restarts a failed stage and PipeTo feeds async results back into the flow.

The examples repository has runnable projects for standalone, remoting, and cluster mode.

AI agents

An Agent is an actor whose decision is made by a model.

On a message, an actor may send messages, create actors, and choose how it handles the next one. An agent step does the same three things: it calls tools and peers, spawns workers, and updates its memory and plan. GoAkt runs that step without a goroutine per agent, and the guide traces every claim to a documented feature.

Sessions the runtime manages

One grain per conversation: activated on the first message, passivated when idle, claimed once across the cluster, relocated on node loss.

Model calls that never block

PipeTo runs the call off the message loop, and a deferred reply under reentrancy answers the caller when the model does.

Failure handled by the runtime

A failed call comes back as a message. A crashed handler goes to its supervisor, with a restart budget and backoff, and no other agent sees a half-finished mutation.

Multi-agent by construction

Orchestrators spawn and watch workers, work-pulling keeps a job alive when its worker dies, and the same code runs in one process or a cluster.

Numbers

Every figure reproduces from the repository.

13.2Mmsg/s
One actor, one sender
Contention-free dispatch: the per-message cost of Tell.
27.2Mmsg/s
Eight actor pairs in parallel
Aggregate throughput, one private receiver per sender.
1.23KB / actor
One million live actors
Resident memory per actor under sustained load.
609B / grain
One million live grains
Resident memory per grain under sustained load.
Run
2026-09-11
Commit
4eec50ab
Hardware
Apple M1, 8 threads
Go
1.27.1

Throughput figures are the median of ten runs. Memory figures are resident heap per actor and per grain after spawning one million actors or activating one million grains. Commands and methodology are in benchmark/doc.md.

Start

Paste the program above into main.go. Then three commands.

$ go mod init quickstart
$ go get github.com/tochemey/goakt/v4
$ go run .