Skip to content
Version: XState v5

Spawn

Sometimes invoking actors may not be flexible enough for your needs. For example, you might want to:

  • Invoke child machines that last across several states
  • Invoke a dynamic number of actors

You can do this by spawning an actor instead of invoking. Actors created by spawning are spawning actors, and actors created with invoke are invoking actors.

There are two ways to spawn: the spawnChild action creator, or the spawn helper function for assign.

In most cases, prefer spawnChild, which causes an actor to be spawned, and can accept a configurable ID for the actor to reference it later:

createMachine({
entry: spawnChild(childMachine, {
id: 'child',
}),
});

You can use spawnChild for multiple spawned actors:

createMachine({
entry: [
spawnChild(childMachine, { id: 'child-1' }),
spawnChild(childMachine, { id: 'child-2' }),
spawnChild(childMachine, { id: 'child-3' }),
],
});

You can also use the spawn helper function provided by the assign action creator, which allows you to store a reference to the spawned actor (an ActorRef) in the machine's context:

const parentMachine = createMachine({
entry: [
assign({
childMachineRef: ({ spawn }) => spawn(childMachine, { id: 'child' }),
}),
],
});

However, if you use spawn, make sure you remove the ActorRef from context to prevent memory leaks when the spawned actor is no longer needed:

actions: [stopChild('child'), assign({ childMachineRef: undefined })];

You can spawn as many actors as you need:

const childMachine = createMachine({
/* ... */
});

const parentMachine = createMachine({
entry: [
assign({
childMachineRefs: ({ spawn }) => [
spawn(childMachine),
spawn(childMachine),
spawn(childMachine),
],
}),
],
});

If you don’t need to keep track of a reference to the spawned actor (e.g.: for anonymous spawned actors), you can use the spawnChild action creator. It does not return a reference, but indicates to the XState interpreter that a new actor should be spawned:

createMachine({
entry: spawnChild('workflow', {
id: 'workflow',
}),
});

API​

actions: assign({
ref: ({ spawn }) => spawn(fromPromise(...), {
id: 'some-id',
})
})
  • spawn(actorBehavior, options?)
    • actorBehavior - The behavior of the actor to spawn. This can be a function, promise, observable, or callback.
    • options - Options for spawning the actor.
      • id (optional) - The ID of the actor. This is used to reference the actor in the state machine.
      • input (optional) - The input to pass to the actor.
      • systemId (optional) - A string identifing the actor, unique system-wide.

Source​

  • Inline: spawn(fromPromise(...))
  • Referenced: spawn('getUser')
    • .provide({ actors })

Lifecycle​

  • Created & started when spawned
  • Stopped when the machine is stopped
  • Can be manually stopped

Stopping an actor​

You can stop a child actor via the "stop child" action. This action is created from the stopChild(id) action creator.

import { setup, stopChild, fromPromise } from 'xstate';

const machine = setup({
actors: {
something: fromPromise(async () => {
// Some actor logic
return 'Some response';
}),
},
}).createMachine({
context: ({ spawn }) => ({
something: spawn('something', { id: 'thing' }),
}),
// ...
on: {
'thing.stop': {
actions: stopChild('thing'),
},
'thing.stopFromContext': {
actions: stopChild(({ context }) => context.something),
},
},
});

Stopping a child actor does not remove it from context. To remove it from context, use the assign(...) action creator:

import { setup, stopChild } from 'xstate';

const machine = setup({
// ...
}).createMachine({
context: ({ spawn }) => ({
something: spawn('something', { id: 'thing' }),
}),
// ...
on: {
'thing.stop': {
actions: [stopChild('thing'), assign({ something: undefined })],
},
},
});

Spawn and TypeScript​

Coming soon

Spawn cheatsheet​

Coming soon