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
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.
Your first actor
One struct, one Receive method, one message at a time.
This is the whole program from the quickstart. Nothing is elided.
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.
- 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.
What is in the box
One import path. Every piece links to its guide.
Actors
Lifecycle, mailboxes, behaviors, stashing, routers.
ExploreSupervision
Directives, restart budgets, backoff, death watch.
ExploreGrains
Activated on first message, passivated when idle, addressed by name.
ExploreClustering
Placement, partition hashing, relocation, singletons.
ExploreRemoting
Tell and Ask across processes, TLS, pluggable serialization.
ExploreStreams
Backpressured, composable stages that talk to actors.
ExploreAlso in the box
- Reliable deliveryPoint-to-point and work-pulling delivery across the cluster.
- Pub/SubTopics on a single node or across the whole cluster.
- Distributed dataCRDTs replicated across the cluster.
- SchedulingDeferred and recurring messages.
- PassivationIdle and capacity-based eviction so memory tracks the working set.
- ObservabilityOpenTelemetry metrics, the event stream, dead letters.
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.
Start
Paste the program above into main.go. Then three commands.
$ go mod init quickstart
$ go get github.com/tochemey/goakt/v4
$ go run .