Skip to content
Version: XState v5

Systems

An actor system is a collection of actors that can communicate with each other. Actors can invoke/spawn other actors, which forms a natural hierarchy of actors that belong to the same system.

In XState, a system is implicitly created from the root actor, which is the actor that is returned from createActor(machine).start(). The system can be accessed from the actor.system property of actors, and from the destructured { system } property from state machine actions:

import { createMachine, createActor } from 'xstate';

const machine = createMachine({
entry: ({ system }) => {
// ...
},
});

const actor = createActor(machine).start();
actor.system;

The root of a system can also be explicitly assigned a systemId in the createActor(...) function:

import { createActor } from 'xstate';

const actor = createActor(machine, {
systemId: 'root-id',
});

actor.start();

This is useful for actors in the system to be able send events to the root actor.

Actor registration​

Actors can be registered with the system so that any other actor in the system can obtain a reference to it.

Invoked actors are registered with a system-wide systemId in the invoke object:

import { createMachine, createActor } from 'xstate';

const formMachine = createMachine({
// ...
on: {
submit: {
actions: sendTo(({ system }) => system.get('notifier'), {
type: 'notify',
message: 'Form submitted!',
}),
},
},
});

const feedbackMachine = createMachine({
invoke: {
systemId: 'notifier',
src: notifierMachine,
},
// ...
states: {
// ...
form: {
invoke: formMachine,
},
},
});

const feedbackActor = createActor(feedbackMachine).start();

Spawned actors are registered with a system-wide systemId in the 2nd argument of the spawn function:

import { createMachine, createActor, assign } from 'xstate';

const todoMachine = createMachine({
// ...
});

const todosMachine = createMachine({
// ...
on: {
'todo.add': {
actions: assign({
todos: ({ context, spawn }) => {
const newTodo = spawn(todoMachine, {
systemId: `todo-${context.todos.length}`,
});

return context.todos.concat(newTodo);
},
}),
},
},
});

Actor communication​

You can also reference a specific actor from the system using system.get('actorId'):

Stopping a system​

  • Stop from root actor: actor.stop()
  • Cannot stop from descendant actors
    • Warning will be logged

Systems and TypeScript​

  • invoke.systemId
  • spawn(thing, { systemId })
  • system.get('actorId')
  • rootActor.stop()

System cheatsheet​

Cheatsheet: actor system​

import { createMachine, createActor } from 'xstate';

const machine = createMachine({
entry: ({ system }) => {
// ...
},
});

const actor = createActor(machine).start();
actor.system;

Cheatsheet: explicitly assign a systemId​

import { createActor } from 'xstate';

const actor = createActor(machine, {
systemId: 'root-id',
});

actor.start();

Cheatsheet: register an invoked actor with the system​

import { createMachine, createActor } from 'xstate';

const formMachine = createMachine({
// ...
on: {
submit: {
actions: sendTo(({ system }) => system.get('notifier'), {
type: 'notify',
message: 'Form submitted!',
}),
},
},
});

const feedbackMachine = createMachine({
invoke: {
systemId: 'notifier',
src: notifierMachine,
},
// ...
states: {
// ...
form: {
invoke: formMachine,
},
},
});

const feedbackActor = createActor(feedbackMachine).start();

Cheatsheet: register a spawned actor with the system​

import { createMachine, createActor, assign } from 'xstate';

const todoMachine = createMachine({
// ...
});

const todosMachine = createMachine({
// ...
on: {
'todo.add': {
actions: assign({
todos: ({ context, spawn }) => {
const newTodo = spawn(todoMachine, {
systemId: `todo-${context.todos.length}`,
});

return context.todos.concat(newTodo);
},
}),
},
},
});