Skip to content

What is actor-ts?

actor-ts is a runtime for building concurrent, distributed, and fault-tolerant systems in TypeScript using the actor model — the same mental model the JVM world has had in Akka and Pekko, .NET has had in Orleans and Akka.NET, and Erlang has had since the 80s. It runs natively on Bun, Node.js 20+, and Deno 2+, picking the right runtime backend (TCP sockets, worker threads, SQLite, HTTP serve primitives) automatically based on which globals are present.

An actor is a small unit of state and behaviour that processes one message at a time. Actors don’t share memory; they communicate by sending messages to each other’s mailboxes. A mailbox is just a queue, and the actor’s loop is “pop a message, run the handler, repeat.” Because there’s no shared state and exactly one message in flight per actor, you don’t need locks, you don’t need careful sequencing, you don’t reason about race conditions inside an actor — the model gives you serializability for free. Actors form supervision trees: when a child crashes, its parent gets to decide whether to restart it, escalate the failure, or shut it down. The same model scales from a single process to a cluster of machines via location transparency — an ActorRef doesn’t know or care whether the actor it points at lives in the same process, another process, or another data centre.

That’s the conceptual core. Everything else — sharding, persistence, distributed data, cluster membership, pub-sub — is built on top of that one primitive.

The actor model has been the production answer for highly concurrent backends for forty years. Telecom switches run on it. WhatsApp ran tens of millions of concurrent connections per Erlang node. LinkedIn, Verizon, Tesla, Hootsuite, Iron.io, Walmart Canada all have Akka stories. The model is battle-tested, the literature is extensive, and the design wins out over thread-pool-plus-mutex code the moment your concurrency picture gets non-trivial.

TypeScript is the dominant language for application backends today. Bun, Node 20+, and Deno 2+ all give you fast startup, solid TypeScript ergonomics, and a healthy ecosystem. Yet the actor-model toolkit for TS has historically been thin — you’d either write your own primitives, glue together promise/worker-thread soup that approximated actors badly, or accept that “anything beyond a toy needs the JVM.”

actor-ts is the answer to “what if we just had Akka over here?” A from-scratch port of the actor-model stack — actors, supervision, cluster, sharding, persistence, observability, HTTP, brokers — built in idiomatic TypeScript, leaning on the type system where Akka’s Scala API used trait composition and Akka’s typed API used type parameters.

A docs reader looking for “an actor library for TS” finds a few on npm. Most of them stop at the basic actor abstraction: a class with a message-handler. That’s the easy part. The hard parts — the ones the Akka community spent two decades getting right — are the operational pieces around the actor.

actor-ts tries to ship them all in one package:

  • Clustering — gossip-based membership with leader election, weakly-up transitions, φ-accrual failure detection, split-brain resolvers. None of this is something an application developer should write themselves.
  • Sharding — for stateful actors that live forever, you need to distribute them across the cluster, remember which node holds which entity, and rebalance when nodes join or leave. Sharding handles the coordinator, the hand-off, the passivation, the remember-entities backend.
  • PersistencePersistentActor for event-sourced state, DurableState for the simpler “save a snapshot” case, both with pluggable journals (in-memory, SQLite, Cassandra) and snapshot stores. Plus the migration toolchain for evolving schemas without rewriting old events.
  • Distributed data — eight CRDTs (counters, registers, sets, maps) with durable storage and gossip replication, for state that should converge across the cluster without leader coordination.
  • Integrations — HTTP server with a route DSL (Fastify default, Express + Hono backends), brokers for Kafka / MQTT / NATS / AMQP / Redis Streams / gRPC / WebSocket, object storage for S3 / MinIO / R2 / filesystem with compression + encryption.
  • Observability — Prometheus metrics, OpenTelemetry tracing, management endpoints, stock metrics out of the box.

The full feature catalogue sits in the left sidebar — Build Actors, Distribute, Persist, Integrate, Observe. Each section has an overview page that explains the why of its subsystem; each subsystem has its own pages going into detail.

The shape of the API surface, and the names of most concepts, will feel familiar to anyone who has used AkkaActorRef, Props, tell / ask, become / stash, supervision strategies, the extensions API, the receptionist, distributed pub/sub, cluster singleton. Where the JVM idioms didn’t carry, we picked the TypeScript-native equivalent — discriminated unions for messages, match().exhaustive() for handlers, peer-dependency-gated extensions for optional integrations.

It is — a serious, full-coverage actor-model toolkit, with a documentation site, runnable examples (chat, voice), and test coverage well into four digits. Production-shaped: the kind of thing you’d build a real backend on, if you were inclined.

It isn’t — battle-tested at scale. Nobody is running ten million concurrent connections on this today. The framework is pre-1.0; the API surface is broad but not all of it is set in stone. And it was written with heavy AI pair-programming assistance, which is a strength (consistency, coverage, comments) and a caveat (some corners may be more “looks right” than “verified right”).

The framework treats the three runtimes — Bun, Node 20+, Deno 2+ — as first-class peers. All three are CI-tested for the features they support; the compatibility matrix is the definitive reference for what works where.

Bun is the primary development target: fastest cold start, built-in SQLite via bun:sqlite, built-in WebSocket server, native test runner. Most internal benchmarks were measured on Bun.

Node is the production reality: by far the most common deployment environment, the runtime your infrastructure team already knows, most npm packages are first-tested against. Some actor-ts features (native WebSocket, native zstd compression) require Node 22+ to avoid a peer-dependency fallback; everything else works on Node 20+.

Deno is the best-effort runtime: works for most features via the npm: specifier, but a handful of integrations have not been exhaustively tested.

Internal abstractions live behind small src/runtime/* modules that auto-detect at startup. You write your application code once; the runtime adapter picks the right backend.

  • Want to try it? Quickstart — five minutes to a running actor.
  • Want the philosophy first? Why actors? — what the actor model gives you that promise-and-worker code doesn’t.
  • Installing? Installation — full walkthrough including the optional peer dependencies.
  • Lost in the surface area? Learning path — suggested reading order based on what you want to build.
  • Coming from Akka, Pekko, Orleans, or Akka.NET? The migration guides map concept-by-concept from those frameworks to actor-ts.