Actor model
Many small stateful objects, each with a mailbox, that handle one message at a time and are spread across a cluster by their ID.
4 technologies on this page ↓How it works
An actor is a small object that owns some private state and a mailbox. Nothing outside can read or change that state; other code can only send the actor a message, which lands in its mailbox. The runtime takes one message at a time from the mailbox and runs the actor’s handler on it, so the code inside reads like plain sequential code with no locks. Concurrency comes from having many actors: an idle actor is just an object in memory, so a single process can hold millions of them on a small pool of threads. While handling a message an actor can update its state, send messages, reply, or create child actors. Actors form a tree, and a parent supervises its children: when one fails, the parent restarts it with fresh state, stops it, or lets it carry on, instead of every caller handling the error. An actor reference works the same whether the actor is in the same process or on another machine (location transparency), so the runtime can spread actors over a cluster. With sharding, each actor has an ID such as cart-4812; the runtime hashes the ID to a shard, runs that shard on exactly one node, routes every message for that ID there and moves shards when nodes join or leave. Virtual actors, introduced by Orleans and also used by Service Fabric and Dapr, go further: an actor always exists logically, is activated on its first message, is removed from memory when idle and keeps its state in a database. Messages between actors are usually delivered at most once, in order per sender, so state that must survive a crash is persisted (often as events) and important requests are retried. Compared with a queue, which hands each job to any free worker, an actor system routes each message to the one object that owns that ID’s state.
An office where everyone has an in-tray. You never walk over and edit a colleague’s files; you drop a note in their tray. Each person works through their tray one note at a time, can pass notes on or bring in a helper, and a team lead replaces anyone who falls ill. The notes reach the right desk even after people move to another floor.
Reach for it when
- Many independent things with their own changing state: shopping carts, game sessions, chat rooms, devices (“digital twins”)
- State that should have exactly one writer at a time, without database locks or optimistic-retry loops
- Hot state kept in memory for low latency, with changes persisted in the background as events or snapshots
- Long-lived sessions or connections, such as WebSockets, that need a single home that can move when a node goes away
Think twice when
- Stateless request handling; ordinary services or serverless functions are simpler
- Queries across many entities (“all carts over $100”); those need a database or a projection, not thousands of actor calls
- Simple background jobs where any worker will do; a queue and a worker pool is easier to run
- Teams without time to learn asynchronous messaging: at-most-once delivery, message versioning, cluster membership and split-brain handling are real costs, and the runtime becomes a core dependency
A real example
A shop models each cart as an actor. The web tier sends “add sku-9” for cart-4812 to the cluster; the ID hashes to shard 17, which lives on node B. If the cart isn’t in memory, node B starts it and replays its stored events, then applies the command, persists a new event and replies in a few milliseconds. Two fast clicks from the same customer are handled one after the other, never at the same time. When node B is drained for an upgrade, its shards move to nodes A and C, and the next message for cart-4812 restarts the cart there from its events. Carts that see no messages for a few minutes are removed from memory.
Technologies
Specific products, and what each does differently.
Apache PekkoOpen sourceThe Apache-licensed fork of Akka 2.6: actors, cluster sharding, persistence, streams and HTTP for Java and Scala, run by a foundation instead of a company.| Commercial product | Akka (Lightbend, Inc., doing business as Akka) | Business Source License 1.1 since 2.7 (October 2022): free outside production, and each release becomes Apache 2.0 three years after it ships; Apache 2.0 up to 2.6.x | 2026-10-06 | |
Apache Pekko | Open source | Apache Software Foundation | Apache 2.0 | 2026-10-06 |
| Open source | Deno Land Inc. | Apache 2.0 | 2026-10-12 | |
| Commercial product | Cloudflare, Inc. | Proprietary | 2026-10-12 |
What each provider calls it
- AWS
- No managed actor runtime. Teams run Akka, Apache Pekko, Orleans or Dapr on their own compute such as EKS; Orleans and Akka both have plugins that keep actor state in DynamoDB, Orleans can track cluster membership there too, and Akka’s own managed service runs in AWS regions
- Google Cloud
- No managed actor runtime. Teams run Akka, Apache Pekko, Orleans or Dapr on GKE or VMs; Akka’s managed Serverless service runs in Google Cloud regions too, and its BYOC option deploys into your own Google Cloud VPC
- Azure
- Service Fabric Reliable Actors (virtual actors with single-threaded turns); Dapr actors in Azure Container Apps (GA, though Microsoft notes Dapr’s actor SDK packages aren’t compatible yet); Orleans, Microsoft’s own open-source virtual-actor framework, runs on AKS, App Service or Container Apps and stores state in Azure Storage or Cosmos DB
- Open source & others
- Erlang/OTP and Elixir (processes and supervisors on the BEAM VM); Apache Pekko (JVM, Apache 2.0) and Akka (JVM, BSL since 2.7); Microsoft Orleans (.NET, virtual actors, MIT); Proto.Actor (.NET and Go); Dapr actors (a sidecar, any language); Ray actors (Python). Cloudflare Durable Objects is a hosted take on the same idea: one single-threaded object per name, with its own storage
In code · python
# pip install ray (Ray actors: one Python object per cart; its calls run one at a time)
import ray
ray.init()
@ray.remote(max_restarts=3) # restarted if its process dies; in-memory state starts over
class Cart:
def __init__(self, cart_id: str):
self.cart_id = cart_id
self.items: dict[str, int] = {}
def add(self, sku: str, qty: int = 1) -> dict[str, int]:
# no lock needed: calls to this actor run serially, in the order they were sent
self.items[sku] = self.items.get(sku, 0) + qty
return dict(self.items)
def cart(cart_id: str):
# address the actor by name: created on first use, reused afterwards
return Cart.options(name=f"cart-{cart_id}", get_if_exists=True).remote(cart_id)
c = cart("4812")
refs = [c.add.remote("sku-1"), c.add.remote("sku-2"), c.add.remote("sku-1")] # sent at once
print(ray.get(refs[-1])) # {'sku-1': 2, 'sku-2': 1}
print(ray.get(cart("4812").add.remote("sku-3"))) # the same actor, found by nameOften confused with
Where it came from1973–2022
In 1973 Carl Hewitt, Peter Bishop and Richard Steiger proposed building artificial-intelligence programs from a single kind of object, the actor. Numbers, procedures and data structures would all be active agents that do nothing except react to messages, and the formalism had no need for goto, interrupts or semaphores.
Erlang reached the same shape from practical needs. From 1986 Joe Armstrong and colleagues at the Ericsson Computer Science Laboratory looked for a better way to program telephone exchanges, which juggle huge numbers of calls at once and must keep running while faulty parts are fixed. Erlang processes are lightweight, share nothing and talk by asynchronous messages, and the OTP libraries added supervision trees that restart failed processes. Armstrong’s history of the language never mentions Hewitt’s actors. Ericsson built its AXD301 switch this way and released Erlang as open source in December 1998.
Akka brought Erlang-style actors and supervision to the JVM in 2009. In 2014 Microsoft Research described Orleans, whose virtual actors are activated on demand and never explicitly created or destroyed, an idea Service Fabric and Dapr also use. Cloudflare’s Durable Objects (2020) sell the same model as a hosted service.
Why it’s built this way
- Share nothing; communicate only by messages
- Shared memory guarded by locks is hard to get right and doesn’t stretch across machines. A message works the same whether the receiver is in the same process or on another server, which is what lets an actor system spread over a cluster.
- Handle one message at a time
- Each actor’s code can be written as simple sequential code that updates its own state without locks. Parallelism comes from running many actors at once, not from threads inside one.
- Let it crash, and let a supervisor restart it
- In a telephone exchange some errors are inevitable. Erlang/OTP arranged processes in supervision trees, where each supervisor monitors its children and restarts them on failure, so error handling lives in one place and the system keeps running.
- Virtual actors that always exist
- The Orleans team found that popular actor platforms still left developers to handle placement, activation and failure themselves. Making actors logical entities that the runtime activates, places and removes took those problems off the developer.
Timeline
- 1973
Hewitt, Bishop and Steiger propose the actor formalism at IJCAI
- 1986
Work on Erlang begins at the Ericsson Computer Science Laboratory
- 1998
Ericsson announces the AXD301 switch; Open Source Erlang released in December
- 2009
Akka 0.5 brings Erlang-style actors to the JVM
- 2014
Microsoft Research describes Orleans and its virtual actors
- 2020
Cloudflare launches Durable Objects
- 2022
Akka moves to the BSL; the Apache Pekko fork enters incubation
- Hewitt, Bishop and Steiger: A Universal Modular ACTOR Formalism for Artificial Intelligence (IJCAI 1973)
- Joe Armstrong: A History of Erlang (HOPL III, June 2007)
- Erlang/OTP: About (Ericsson Computer Science Laboratory, OTP)
- akka/akka-core on GitHub: tag v0.5 (July 2009)
- Microsoft Research: Orleans, distributed virtual actors for programmability and scalability (MSR-TR-2014-41, March 2014)
- Cloudflare Blog: Introducing Workers Durable Objects (Sep 2020)
- Akka blog: Why we are changing the license for Akka (Jonas Bonér, Sep 2022)
- Apache Incubator: Pekko project status (entered incubation October 2022)
Sources22
- Akka docs: What problems does the actor model solve? (mailboxes, behavior)
- Akka docs: Message delivery reliability (at-most-once, ordering per sender–receiver pair)
- Akka docs: Cluster Sharding (entities by ID, one place in the cluster)
- Akka docs: Fault tolerance (supervision, restart)
- Akka docs: Akka Persistence DynamoDB
- Akka blog: Akka 3 FAQ (Serverless regions on AWS and Google Cloud, BYOC)
- Erlang/OTP docs: Design principles (supervision trees)
- Elixir: home page (runs on the Erlang VM)
- Microsoft Learn: Orleans overview (virtual actors, grains, silos, hosting options)
- Microsoft Learn: Orleans grain persistence (Azure Storage, Cosmos DB, DynamoDB providers)
- Microsoft Learn: Orleans cluster management (DynamoDB membership table)
- dotnet/orleans on GitHub (MIT licence)
- Microsoft Learn: Introduction to Service Fabric Reliable Actors
- Dapr docs: Actors overview (virtual actors, placement, turn-based access)
- Microsoft Learn: Dapr in Azure Container Apps (actors GA, SDK compatibility note)
- Ray docs: Actors (methods on one actor run serially)
- Ray docs: Named actors (get_if_exists)
- Ray docs: Actor fault tolerance (max_restarts)
- Proto.Actor for .NET on GitHub
- Proto.Actor for Go on GitHub
- Cloudflare docs: What are Durable Objects? (actor programming model, single-threaded, private storage)
- Apache Pekko: home page