Your first actor
We'll build the smallest useful actor — a counter — and drive it. Every code block on this page is type-checked against the real @actor-web/runtime types when the site builds, so what you see compiles.
1. Define the behavior
An actor's behavior is authored with defineBehavior. You declare the message union it accepts, give it an initial context, and handle each message by returning the next context.
ts
import { defineBehavior } from '@actor-web/runtime';
// The messages this actor accepts.
type CounterMessage = { type: 'INCREMENT' } | { type: 'DECREMENT' };
export const counter = defineBehavior<CounterMessage>()
.withContext({ count: 0 })
.onMessage(({ message, context }) => {
switch (message.type) {
case 'INCREMENT':
return { context: { count: context.count + 1 } };
case 'DECREMENT':
return { context: { count: context.count - 1 } };
}
})
.build();A few things to notice:
- The handler receives
{ message, context, actor, tools }. Here we only needmessageand the currentcontext. - Returning
{ context }replaces the actor's state — the OTPgen_serverpattern. Return nothing to leave state unchanged. countis inferred asnumberfromwithContext({ count: 0 }), socontext.count + 1is checked. Try changing it to a string and the build fails.
2. What a handler can return
A handler returns an ActorHandlerResult, any of these fields:
context— replace this actor's state.reply— respond to anask(...)caller (1-to-1).emit— broadcast domain events to subscribers (1-to-many). This is how other actors react to you — see Subscriptions & events.
ts
type CounterMessage = { type: 'INCREMENT' } | { type: 'DECREMENT' };
const counter = defineBehavior<CounterMessage>()
.withContext({ count: 0 })
.onMessage(({ message, context }) => {
if (message.type === 'INCREMENT') {
const count = context.count + 1;
// Update state AND announce the change as a fact.
return { context: { count }, emit: [{ type: 'COUNT_CHANGED', count }] };
}
return { context: { count: context.count - 1 } };
})
.build();Next steps
- Subscriptions & events — let another actor react to
COUNT_CHANGED. - More to come: wiring a topology, running a local runtime, and consuming an actor from a UI.