Open-source project
asynkron/protoactor-go avatar
asynkron/protoactor-go

asynkron/protoactor-go: distributed actors in Go over gRPC and Protobuf

Proto Actor - Ultra fast distributed actors for Go, C# and Java/Kotlin

5,511 stars572 forksGoApache-2.0

At a glance

What is it?
Proto Actor's Go implementation gives you Akka-style actors without a custom runtime underneath: gRPC streams carry the messages, Protobuf defines them, and Consul, etcd or ZooKeeper handle cluster membership. The README still calls the Go API beta, and the last release was 0.4.0.
Who is it for?
Adopt protoactor-go when you need actors that can move from one process to another and you are willing to pin a beta API; the README's own caveat is that the API may change until 1.0, so pin a commit rather than tracking dev. Skip it if you only need in-process concurrency, where goroutines and channels carry less machinery.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 175 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What protoactor-go solves, and who it is aimed at

Go gives you goroutines and channels, and for a single process that is usually enough. The moment state has to live somewhere specific, survive a restart, or be addressed from another machine, channels stop helping. Proto Actor's answer is the actor model: a process holds an address, a mailbox and a behavior, and you talk to it by sending messages rather than by calling methods.

The repository is the Go implementation of Proto Actor, and the README states it is cross platform with the C# implementation in asynkron/protoactor-dotnet. That cross-platform claim is the differentiator. The README's stated reason is exit strategy: if an organization migrates from .NET to Go, actor services on both sides can still communicate. If you are building a single-language Go service and will never have a .NET or JVM peer, that argument does not apply to you.

The README also carries a warning that matters more than any feature list: the Go implementation is still in beta, users are already running it in production, and the API may change until 1.0. The last release listed in the repository is 0.4.0, from 2024-04-03. Treat the version number as honest signalling rather than a maturity claim.

How remoting works: gRPC streams, Protobuf, and the design principles behind them

The README's design principles are unusually explicit, and they explain most of the architecture. Minimalistic API, build on existing technologies, pass data not objects, be fast. The second principle is the load-bearing one: networking is gRPC streams and clustering is Consul.IO, rather than a hand-written transport and membership protocol.

Serialization is not hidden. The README says Protobuf all the way, and the repository layout backs that up: there is a protobuf/ directory, a buildall.sh invoked by the Makefile's proto target, and an updateproto.bat for Windows. Messages you send across a node boundary have to be Protobuf types. That is a deliberate constraint, and it is the reason the Go and C# sides can interoperate at all.

The lifecycle model differs from Akka in a way worth knowing before you port anything. The README states that Proto Actor uses messages for lifecycle events instead of OOP method overrides, so an actor's Receive method switches on *actor.Started, *actor.Stopping and *actor.Stopped. If you have written Akka or Akka.NET actors, your preStart and postStop hooks become message cases. Behavior changes work the same way: SetBehavior, PushBehavior and PopBehavior swap the function that handles the next message, which the README demonstrates with a two-state actor.

The performance claim in the README is specific: over two million messages per second between nodes using two actors, with message order preserved, described as six times the UDP-based Artery transport in Scala Akka and 30 times Akka.NET. Those are the project's own numbers from its own benchmark, and the README does not describe the hardware or the message shape, so do not treat them as a prediction for your workload.

Installing protoactor-go and sending your first message

The README's building section assumes a configured GOPATH and the standard Protocol Buffer implementation installed, then uses go get and make. On a modern Go module setup you can pull the module directly. The repository's go.mod declares the module path as github.com/asynkron/protoactor-go and requires Go 1.25.3, so check your toolchain before anything else.

bash
go get github.com/asynkron/protoactor-go

That fetches the library. You only need the full make build if you intend to regenerate the Protobuf definitions yourself, which the README describes as go get ./... followed by make inside the checkout. The Makefile's proto target runs buildall.sh.

The README's hello world is the shortest real use. It defines a message type, an actor whose Receive switches on that type, and spawns it from actor.EmptyRootContext. Note that PropsFromProducer takes a factory function, not an instance.

go
type Hello struct{ Who string }
type HelloActor struct{}

func (state *HelloActor) Receive(context actor.Context) {
    switch msg := context.Message().(type) {
    case Hello:
        fmt.Printf("Hello %v\n", msg.Who)
    }
}

func main() {
    context := actor.EmptyRootContext
    props := actor.PropsFromProducer(func() actor.Actor { return &HelloActor{} })
    pid, err := context.Spawn(props)
    if err != nil {
        panic(err)
    }
    context.Send(pid, Hello{Who: "Roger"})
    console.ReadLine()
}

Running that prints Hello Roger. console.ReadLine() is a placeholder from the README to keep the process alive; in a real program you would block on whatever your service waits for.

To run the tests locally, the Makefile defines a test target that filters packages. Note what it excludes, because it tells you which parts are not covered by a plain make test.

bash
go test `go list ./... | grep -v "/examples/" | grep -v "/persistence" | grep -v "/scheduler"`

If you want to try clustering, the repository ships a docker-compose.yml with consul on port 8500, etcd on 2379, and zookeeper mapped to host port 8000. The README's own testing note says the Consul integration tests need Consul running, which is what that compose file is for.

Where protoactor-go is the wrong tool

The beta label is not decoration. The README says the API might change until 1.0, and with 0.4.0 as the most recent release listed, a minor version bump can carry a breaking signature change. If your team cannot absorb that, this is the wrong library regardless of how well the actor model fits.

Serialization is the second boundary. Because Protobuf is explicit and mandatory for anything crossing a node, you cannot send arbitrary Go structs or interfaces over remoting. Every message type needs a Protobuf definition and a regeneration step through buildall.sh. For a codebase that already uses Protobuf this is free; for one that does not, it is a build pipeline you now own.

The lifecycle-as-messages design is a real trade-off, not a strict improvement. Anything you would do in a constructor or destructor has to be expressed as a case in Receive, and mistakes there are easy to make because the compiler will not tell you that you forgot to handle *actor.Stopping.

Finally, if your problem is in-process concurrency, the actor machinery is overhead. Goroutines and channels are in the standard library, need no serialization boundary, and have no beta API to track. Proto Actor earns its place when actors need addresses that outlive a single process.

Alternatives: GoAkt and plain goroutines with channels

GoAkt is a Go actor framework with a similar model, and it appears in the searches people run around this project. The difference in approach is the dependency story: protoactor-go deliberately builds on gRPC streams for transport and Protobuf for serialization, and its README frames cross-platform compatibility with the C# implementation as the point. If you have no .NET or JVM peer to talk to, that interoperability buys you nothing and you are carrying the Protobuf toolchain for its own sake. GoAkt is a purely Go-side choice, which removes the cross-language constraint but also removes the exit strategy the README argues for.

The other alternative is not a framework at all. For a service where all state fits in one process, goroutines, channels and a mutex around a map will be less code and fewer moving parts than any actor runtime. The README's own framing supports this: the actor model is presented as a way to get decoupled concurrency, distribution by default and fault tolerance, and the first of those three is the only one the standard library does not already give you.

Maintenance, upgrades and what Apache-2.0 means here

The repository is not archived, and the last push was on 2026-04-08. The release history is sparse: 0.4.0 on 2024-04-03, 0.3.0 on 2023-10-13, 0.2.0 on 2022-04-15. Commits land on the dev branch between releases, so a team that wants fixes without a tagged version has to track dev and accept the API churn the README warns about. A team that pins releases gets stability at the cost of waiting.

Upgrade cost is concentrated in two places. The Protobuf definitions under protobuf/ are regenerated by buildall.sh, so a dependency bump that touches message shapes means re-running the proto target and rebuilding your own generated code. And the dependency list in go.mod is long, including gRPC, OpenTelemetry, the Consul API, etcd client, ZooKeeper client and Kubernetes client libraries. The cluster providers you do not use still sit in the module graph, which affects build times and the surface you audit.

The licence is Apache-2.0, which permits commercial use and modification and includes an explicit patent grant. It also requires that you preserve copyright and licence notices and state significant changes. That is a summary of the licence text, not legal advice; if you are redistributing a modified protoactor-go, have counsel read the NOTICE and attribution requirements against your distribution model.

Editorial conclusion

Adopt protoactor-go when you need actors that can move from one process to another and you are willing to pin a beta API; the README's own caveat is that the API may change until 1.0, so pin a commit rather than tracking dev. Skip it if you only need in-process concurrency, where goroutines and channels carry less machinery. Before committing, check whether the cluster provider you intend to run is exercised in your own deployment (the Makefile's test target excludes persistence and scheduler packages), and read the Protobuf definitions under protobuf/ to confirm the wire format matches your cross-platform peers.

Frequently asked questions

What is protoactor-go?

It is the Go implementation of Proto Actor, an actor-model library where messages between nodes travel over gRPC streams and are serialized with Protobuf. The repository also points to a C# implementation, and the README describes the two as cross platform.

Is protoactor-go production ready?

The README says the Go implementation is still in beta, that there are already users running it in production, and that the API might change until 1.0. The most recent release listed is 0.4.0 from 2024-04-03.

How do I install protoactor-go?

The module path is github.com/asynkron/protoactor-go, so go get github.com/asynkron/protoactor-go fetches it. The README's building section instead assumes a configured GOPATH plus the standard Protocol Buffer implementation, then runs go get ./... and make inside the checkout.

Does protoactor-go need Consul to run?

Only for clustering. The repository's docker-compose.yml starts Consul, etcd and ZooKeeper as cluster provider options, and the README notes that the Consul integration tests require Consul to be running. The core actor API works without any of them.

What is the Actor Design Pattern?

It is the model protoactor-go implements: independent actors that hold state, receive messages into a mailbox, and change behavior in response, with lifecycle signalled by messages such as *actor.Started and *actor.Stopped rather than method overrides. The README lists decoupled concurrency, distribution by default and fault tolerance as the reasons to use it.

Official sources

  1. asynkron/protoactor-go on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/asynkron-protoactor-go.svg)](https://hysenlabs.com/projects/asynkron-protoactor-go)