Actix, Riker... or?

What framework do you recommend for the actor model?
What are your experiences?

Actix framework
Riker framework
Axiom framework


Here are another three:

Bastion framework
Kay framework
xtra framework

I am also very interested in finding out how to choose among all these options.

Not that this is any valuable indicator, but I just sorted them by GitHub stars while looking at their repos:

Actix: 4.7k
Bastion: 1.2k
Riker: 480
Kay: 235
Axiom: 78
xtra: 10


I think these are a few criteria:

  • does it have the features you need? Remote actors? Can you send several types of message to one actor type? Wasm support? Possibility to run cpu intensive actors? Can you decide which actors go in which threads? Priorities for messages? What's debugging like? Possible to follow the flow of messages in your logs? Does it compile on stable?
  • what would it take to implement features you need but aren't provided. Is the code a mess? Is it maintainable, scalable, full of unsafe, well written with loose coupling and thight cohesion? How long does it take you to even understand it's design? How many SLOC for similar functionality? Is the API nice? Is it well documented?

They are popping up like mushrooms these days, there is also Stakker, Actori. I'm even working on an actor library of my own, but that isn't published yet, so I won't propose you consider it.


Having some kind of chart for comparison would be really helpful here.

1 Like

Stakker is mine, based around qcell for the borrowing. I have a version 0.0.2 on the go, with a lot of changes (really a lot). It's focussed on being low-overhead and small, and being able to run on top of any event loop you like, e.g. whatever legacy codebase you need to integrate into. It will never have all of the features of the big names, because that's not the aim. It aims to be solid from the ground up. The only unsafe you need to tolerate is qcell, the rest of it can be turned off. I'm keeping version numbers low to manage expectations for now. However when it does eventually stabilise, the feature-set it ends up with will be maintained, for sure, because it is being used.

Like you say, they're popping up like mushrooms, and some are dying off similarly. I looked at some of the other crates before I started mine (quite a while back), but either they were obviously heading in quite a different direction to where I needed to go, or there was something fundamentally broken that looked too hard to fix. It's too late to start considering some of the newer ones now!


Since I am about to do the final stretch for my actor library, I'm planning on reviewing all existing ones, to check for good ideas at least. I might publish some comparison.

I'll keep your wish in mind.


From this thread and elsewhere, I was able to locate 12 existing frameworks. Six of them have been updated in the previous 6 months and the rest not. Sorted by GitHub stars in each group:

Recently updated:


Not recently updated:


@najamelan I look forward to seeing your review.

1 Like

Note that there are multiple libraries that use a pre 1.0 policy where breaking changes are in the minor version. So 0.1 to 0.2 but not 0.1.1 to 0.1.2. This way many people are pinning 0.X (here 0.2 for example) for pre-release crates in their cargo.toml.

Yes, but a lot of crates in the 0.1 or 0.2 or 0.3 range are considered stable and maybe even finished. So I don't want people to make that assumption. I'd rather be able to change stuff freely until I'm reasonably certain I've got things right and how I want them, without causing a lot of breaking changes for others. If anyone feels that Stakker's direction is close to ideal for what they need for their project, perhaps it would be good to get involved early. Let me know and I will see if I can take into account the requirements you have.

Oh I've also used some crates where they explicitely warned that there will some more iterations. I still kept up with their changes, because their core functionality was nice and the iterations improved the API. Or as rustc does it: Prevent people from using unstable assumptions as stable. So please make breaking changes from 0.X to 0.X+1, so people don't get used to stable stuff and start complaining :stuck_out_tongue:

0.0.1 to 0.0.2 is also allowed to be a breaking change (as I understand it) as it's the first non-zero number changing that is significant in cargo semver. But anyway I will probably go to 0.1 fairly soon.

one thing you can do is 0.1.0-alpha.1. This makes it kind of obvious. It does break some things like showing the latest version in if I recall right.

Does any of these frameworks support Any type?

What do you mean? std::any::Any is a trait, not a type.

I'm pretty sure you can put Box< dyn Any + Send + Sync > in an actor message, probably on all of them, if that's what you are asking.

I've got version 0.0.2 of Stakker out now, since people are comparing the crates. There is a bit more coverage testing code that needs adding, but it's mostly there (87% coverage including macros). It's working fine for my current projects, but I really need to find a complicated project to do with it to stretch it now, to see if anything else needs changing. So I'll let it sit at 0.0.? for the moment.

I'm also interested if anyone does a survey of the current actor crates.

Here is another one: acteur

Found another one:


According to async-rs/async-std, this actor framework belongs to the async-std ecosystem.

My rust/actor experience so far is limited to using Axiom (which I think is impressive). I'm particularly interested in being able to combine synchronous and asynchronous communication efficiently in a single actor framework. Hence my interest in combining different frameworks.

Stakker offers a variety of thread/process/distributed? options/features for running actors. Can you give some brief example descriptions that will help to understand the trade-offs and decide which of the following options to choose from:

  • inter-thread : Enables inter-thread operations such as Waker and PipedThread .
  • multi-thread [Optional]: Specifies that more than one Stakker will run in the process, at most one Stakker per thread. This disables some optimisations that require process-wide access.
  • multi-stakker [Optional]: Specifies that more than one Stakker may need to run in the same thread. This disables optimisations that require either process-wide or thread-local access.


Stakker always has the same API and behaviour. It's just the implementations that are changed underneath. So to start with you don't need to worry about the features. Just start by using the default features, which should suit non-advanced uses of Stakker. (If you need to enable another feature because you're running multiple Stakker instances at the same time, you'll know because you'll get a panic which tells you what to do. inter-thread is already enabled, so you'll have Waker and PipedThread available by default. )

What Stakker offers is just the minimum wrapping around a single-threaded event loop to make coding safe and comfortable in an actor style (IMHO). It has a lot in common with Pony, at least some of the aspects, but all done in a Rust way. I developed a similar framework for Lua actors some years ago (not open-source), so have practical experience from that. The model is the traditional single-threaded event loop model, i.e. one thread is in charge of all the I/O events, and then will offload heavy work to other threads.

However there is nothing to stop you running multiple Stakkers in different threads listening to different event sources. However you'll have to set up your own communication between them (e.g. channels), and actors can't migrate between Stakker instances. So each separate Stakker runtime is its own little world.

You can go a long way performance-wise with a single thread. A single thread can be better than two threads, because you're not paying for synchronization all the time. However if your actor workload needs to be constantly load-balanced over very many threads then Stakker is not suited for that task. It is optimised for the single-threaded case.

So, based on the "main thread" model (e.g. as used by most GUI frameworks and a surprising number of servers), Stakker would run on the main thread, and then for example you can use PipedThread to start other threads to run heavy tasks. So you could integrate with blocking channel-based systems that way, or run rayon jobs or whatever. Using PipedThread means that none of these things will block your main thread. Other kinds of inter-thread interfaces could be developed using Waker, but PipedThread is convenient.

The other thing Stakker is designed to make possible (still needs testing) is running within some other application's event loop, even an event loop from another language. So you'd need to take events from the outer event loop and turn them into calls into actors within Stakker, then run Stakker's queues to completion, and then return to the outer event loop, passing back whatever events your actors wish to forward. If you use timers within Stakker, the next timer expiry would need to be converted into a timer in the outer event loop each time you finish running Stakker queues. Stakker can use whatever time system the outer event loop uses.

So Stakker isn't tied to any particular event loop, or polling call, or time system, or anything. It just provides the actor support for Rust code, and should be able to slot in anywhere it is required. That is the intention at least. It would be good to get some more people trying it, and to hear back from them about any difficulties. It is already being used in the development of a commercial product. I have a couple of personal projects using it too, which I'll open-source eventually.

I will release 0.1.0 soonish as the current feature-set seems to be working pretty well. However I'm still interested in hearing about any problems that people have difficulty solving using Stakker, which might suggest things that might need rearranging.

Thanks you, extremely helpful!