moxzi
Docs / Actor platforms / Motoko actors on actor platforms

Motoko actors on actor platforms

A Motoko actor compiled by moxzi is one .wasm file. You can run it on the Internet Computer, under moxzid, in a browser tab — or on an actor platform your organisation already runs: Dapr, Restate, Orleans, Akka (as Apache Pekko), Proto.Actor, Cloudflare Durable Objects, Temporal, Ray or wasmCloud. The actor does not change; the platform provides what it is good at.

Two forms#

In process (alpha-7)Beside the platform (first built)
Where Motoko runsinside the platform's own process, through the moxzi-rts libraryin a separate moxzi-actor-host service the platform calls over HTTP
Where the actor's state livesthe platform's own store, committed by the platform each turnthe service's disk (a snapshot and a log)
Cost per active actor~110 KiB; activation from the store ~0.4 msa service process per deployment
Update latency vs the platform's own actor1.3–1.5x on Linux (Proto.Actor, Temporal, Restate)one more HTTP hop
Details/docs/hosts/in-process/each platform page below

In both forms the platform drives and Motoko never calls the platform back, which is what lets an await stay outstanding across a crash of either side, or across an upgrade.

Who does what#

The platform ownsMotoko owns
identity: one actor per key Type/idexecuting the actor's code
placement: which machine runs which actortransactional turns: a trap rolls back the whole turn
one message at a time per actorthe await: the caller parks until the answer comes
routing a call from one actor to anotherwhich timers are due and what they run
durable timers (reminders, alarms)upgrades: drain, then migrate the heap
in process: the actor's durable imagebeside the platform: the actor's heap, on the service's disk

Start a project#

moxzi host new <platform> <dir> writes a project that runs a Motoko actor inside the platform's own process: actor.mo (a counter), moxzi's adapter for the platform in host/, and a run.sh that builds both, starts what the platform needs (Postgres in Docker; a Temporal dev server), starts the host, hands it the actor and calls it.

moxzi host new protoactor hello
cd hello && ./run.sh
# Counter/1.inc() -> [1]
curl -X POST localhost:8090/actors/Counter/1/method/inc -H 'content-type: application/json' -d '[]'
Platformhost newNeeds
Proto.ActorprotoactorGo, Docker
DaprdaprGo, the Dapr CLI after dapr init
TemporaltemporalGo, the Temporal CLI, Docker
Orleansorleans.NET 8 SDK, Docker
Akka (Pekko)akkaa JDK and coursier (cs), Docker
RayrayPython 3 with host/requirements.txt, Docker
RestaterestateDocker (the Restate server); the host is prebuilt
wasmCloudwasmcloudnothing else: the wash-runtime host and its components are prebuilt
CloudflarecloudflareNode.js and npm (wrangler dev, local); the engine is prebuilt

host new needs the release's SDK bundle unpacked beside moxzi (moxzi-sdk-<version>-<target>.tar.gz: the runtime library and the adapter sources). Restate, wasmCloud and Cloudflare hosts build against moxzi's own workspace, so a release ships them prebuilt in moxzi-hosts-<version>-<target>.tar.gz (under hosts/) and host new copies them into the project (from the repository: scripts/stage_hosts.sh). Both bundles unpack into the same directory as the toolchain tarball (/docs/hosts/in-process/). scripts/host_new_gate.sh runs each project twice: the first run answers [1], and a second, from a new host process, answers [2], because the state stayed on the platform's side.

Use cases: --example#

moxzi host new <platform> <dir> --example <name> writes a project whose run.sh demonstrates something a platform's own actors usually leave to you (moxzi host examples lists them):

ExampleActorsWhat the demo proves
counter (default)Counterone actor per key; state survives a new host process
ledgerAccounta deposit retried with the same invocation id is applied ONCE, even after the host process restarts; an overdraft traps and the whole turn rolls back; a transfer awaits the other account's credit
sagaTrip, Hotel, Flighta booking parked on an await survives the host process being killed and finishes when the held call is delivered; a full flight triggers a compensating release of the room
moxzi host new orleans shop --example ledger
cd shop && ONCE=1 ./run.sh
# Account/alice.deposit(100), invocation dep-1 -> [100]
# (the host process was killed and started again)
# retry dep-1 after a host restart            -> [100]
# Account/alice.withdraw(500), an overdraft   -> trapped
# Account/alice.balance() after the trap      -> [100]
# Account/alice.transfer("Account/bob", 30) -> [70]
# Account/bob.balance()                       -> [30]

An actor calls another actor by its key through the host's management canister, which answers the principal and learns the route at once (hosted actors only; not a method on the IC):

transient let host : actor { moxzi_actor_of : ({ key : Text }) -> async Principal } = actor "aaaaa-aa";
let bob : actor { credit : (Nat) -> async Nat } = actor (debug_show (await host.moxzi_actor_of({ key = "Account/bob" })));

The keys an actor resolves or calls travel in its image, so nothing is re-learned after a restart. The gate runs both examples on every scaffoldable platform and checks every answer.

What "passes the matrix" means#

Every platform page ends with the same sixteen-row table: the conformance suite (spec §61) run against the real platform, with real process kills and restarts. Persistence, trap rollback, parallelism across machines, duplicate delivery, an await that survives a crash, upgrades while an await is outstanding, timers that survive passivation and crashes, tiny durable writes on a large heap, and ICRC-72 pub/sub on the standard's wire types (oneway notifications, confirmations, and a subscriber that checks the caller). All nine platforms pass all sixteen, in both forms (Cloudflare skips Actor Parallelism locally: wrangler dev runs every Durable Object in one isolate). Run it yourself:

HOST=dapr-inproc scripts/host_matrix_gate.sh   # in process; drop -inproc for the service form
# or restate, orleans, pekko, protoactor, cloudflare, temporal, ray, wasmcloud

Choosing a platform#

On this pageTwo formsWho does whatStart a projectUse cases: --exampleWhat &quot;passes the matrix&quot; meansChoosing a platform