RivetKit Actors
RivetKit Actors are Actors written with Rivet’s own library, as Rivet’s docs describe. Alchemy deploys them as they are: it bundles your entry file and runs it on a pool’s nodes, connected to your control plane.
Write the Actors
Section titled “Write the Actors”Write the file the way RivetKit documents it. It defines the Actors, registers them, and starts the registry:
import { actor, setup } from "rivetkit";
export const counter = actor({ state: { count: 0 }, actions: { increment: (c, x: number) => { c.state.count += x; c.broadcast("newCount", c.state.count); return c.state.count; }, },});
export const registry = setup({ use: { counter } });
registry.start();registry.start() takes no settings. On the pool’s nodes, Alchemy sets RIVET_ENDPOINT, RIVET_TOKEN, RIVET_NAMESPACE and RIVET_POOL, and RivetKit reads them to join the right pool on the right control plane.
Declare it
Section titled “Declare it”Point a Rivet.DurableObject at the file, and give it a pool:
import * as Rivet from "@alchemy.run/rivet";import * as Effect from "effect/Effect";import { Counters } from "./cluster.ts";
export const Counter = Rivet.DurableObject("Counter", { main: "./src/actors.ts" }).pipe( Effect.provide(Counters),);With only main and no implementation, the Durable Object is external. Alchemy bundles src/actors.ts and everything it imports, except rivetkit itself, which the pool’s nodes install. It doesn’t change your code.
main is relative to where you run the deploy.
Give it a pool of its own
Section titled “Give it a pool of its own”The program runs its own process on every node, so its pool runs nothing else:
import * as RivetDocker from "@alchemy.run/rivet/Docker";import * as Layer from "effect/Layer";
export const Cluster = RivetDocker.SwarmControlPlane("Rivet");
export const Counters = RivetDocker.SwarmPool("Counters").pipe(Layer.provide(Cluster));Any pool on any cloud works. A pool given a RivetKit program and another Durable Object fails to deploy with Rivet.PoolProgramConflict.
Reach it from other code
Section titled “Reach it from other code”Callers use RivetKit’s client, as Rivet’s docs describe. The Durable Object’s attributes give them what to connect with: the control plane’s endpoint, the namespace, the pool and the admin token.
const counter = yield* Counter;return { endpoint: counter.endpoint, namespace: counter.namespace, pool: counter.pool };There are no bindings and no yield* calls from other runtimes. For those, write the Actor as a Durable Object.
Next, RivetKit Effect Actors: the same for Rivet’s Effect SDK.