Stately
XState v6 alpha

Machine configuration

Reference for the top-level state machine configuration.

XState v6 is in alpha

APIs and behavior may change before the stable release.

Create state machine logic with createMachine(...).

const machine = createMachine({
  id: 'request',
  context: { attempts: 0 },
  initial: 'idle',
  states: { idle: {}, loading: {} }
});

The root of a machine is a state node. It accepts everything a state node accepts, plus the machine-level properties below.

Machine properties

PropertyTypeDescription
idstringStable identifier for the root state node. Used by #id targets and in state node ids.
descriptionstringHuman-readable description.
contextvalue or ({ input, spawn, actors, self }) => valueInitial context. Required when the context type is not never.
initialstring or { target, input }Initial child state. The object form passes state input.
statesRecord<string, StateNodeConfig>Child state nodes.
onRecord<EventType, TransitionConfigOrTarget>Transitions available in every child state.
entrytransition function or named actionRuns when the machine starts.
exittransition function or named actionRuns when the machine stops.
invokeInvokeConfig or InvokeConfig[]Actor logic invoked for the machine's lifetime.
alwaystransitionEventless transition checked after every microstep.
afterRecord<delay, transition>Delayed transitions.
timeoutnumber, delay name, or functionDeadline for the machine. See timeouts.
onTimeouttransitionTaken when timeout elapses. Required with timeout.
onDonetransitionTaken when a final child state is reached. See final states.
onErrortransitionTaken on xstate.error.* raised below this node. See errors.
outputvalue or ({ context, event }) => valueOutput produced on completion.
schemas{ context, events, emitted, input, output, meta, tags, children, actions, guards }Standard Schema definitions. See TypeScript.
internalEventsreadonly EventType[]Events the machine may raise but no one may send in. See internal events.
actionsRecord<string, (params, args) => void>Named action sources. See setup and provide.
guardsRecord<string, (params, args) => boolean>Named guard sources. See guards.
actorsRecord<string, ActorLogic>Named actor logic sources. See invoke.
delaysRecord<string, number | (args) => number>Named delay sources. See delays.
versionstringThe machine's own version, stamped onto persisted snapshots. See persistence.
migrate(persistedSnapshot, fromVersion) => unknownUpgrades a persisted snapshot whose version does not match. Restoring a mismatched snapshot without it throws.
metaobjectMetadata for the root state node. Must match schemas.meta.
tagsstring[]Tags for the root state node. Must match schemas.tags.
options{ maxIterations }Microstep limit for infinite-loop detection. Defaults to Infinity.

Named actions take their params as the first argument, so they can be called directly or enqueued:

const machine = createMachine({
  actions: { notify: (params: { msg: string }) => toast(params.msg) },
  context: { total: 0 },
  initial: 'cart',
  states: {
    cart: {
      on: {
        checkout: ({ context, actions }, enq) => {
          if (!context.total) return;
          enq(actions.notify, { msg: 'Charging' });
          return { target: 'charging' };
        }
      }
    },
    charging: {}
  }
});

State node properties

Every non-root state node accepts the following. All are optional.

PropertyTypeDescription
initialstring or { target, input }Initial child state. The object form passes state input.
statesRecord<string, StateNodeConfig>Child state nodes.
type'atomic' | 'compound' | 'parallel' | 'final' | 'history'Node kind. See parallel states, final states and history states.
history'shallow' | 'deep' | booleanHistory kind for a history state node.
targetstring | string[]Default target of a history state node.
onRecord<EventType, TransitionConfigOrTarget>Event transitions.
entrytransition function or named actionRuns on entering this state.
exittransition function or named actionRuns on exiting this state.
invokeInvokeConfig or InvokeConfig[]Actors started on entry and stopped on exit.
afterRecord<delay, transition>Delayed transitions scheduled on entry.
timeout / onTimeoutsee aboveState deadline and its transition. See timeouts.
alwaystransitionEventless transition taken while this state is active.
onDonetransitionTaken when a final child state is reached.
onErrortransitionTaken on an error raised at or below this state.
outputvalue or mapperOutput of a final state node.
idstringUnique id, targetable as #id.
routeRouteConfigEnables { type: 'xstate.route', to: '#id' }. Requires an explicit id. See route states.
metaobjectMetadata read with snapshot.getMeta(). See states.
tagsstring[]Tags read with snapshot.hasTag(...).
descriptionstringHuman-readable description.
ordernumberDocument order override.
schemas{ input, ... }Per-state schemas, usually declared in setup({ states }).

A choice state is a different shape: it requires type: 'choice' and a choice function, and accepts only id, tags, meta, description and route. It cannot have states, on, entry, exit, invoke, after, always or output.

const machine = createMachine({
  initial: 'uploading',
  states: {
    uploading: {
      invoke: { src: uploadFile, onDone: { target: 'check' } },
      timeout: 30_000,
      onTimeout: { target: 'failed' },
      tags: ['busy']
    },
    check: {
      type: 'choice',
      choice: ({ context }) => (context.size > 0 ? 'done' : 'failed')
    },
    done: { type: 'final', output: ({ context }) => ({ url: context.url }) },
    failed: {}
  }
});

Sources and implementations

actions, guards, actors and delays can be declared on the machine, or on setup(...) when several machines share them or when per-state schemas are needed. Use machine.provide(...) to replace an implementation without changing the machine structure.

const testMachine = machine.provide({
  actors: { chargeCard: fakeChargeCard }
});

A media player machine may provide browser audio actors in production and fake actors in tests. An order machine may provide different payment actors for development and production.

TypeScript

createMachine(...) infers state keys and literal transition targets from states. Use schemas when events, context, input, output, meta or tags need explicit types, and setup(...) when those types must exist before the machine is written.

Machine cheatsheet

const machine = createMachine({
  id: 'workflow',
  version: '1.0.0',
  schemas: { events: { start: z.object({}), stop: z.object({}) } },
  context: { attempts: 0 },
  initial: 'idle',
  states: {
    idle: { on: { start: { target: 'active' } } },
    active: {
      timeout: 10_000,
      onTimeout: { target: 'idle' },
      on: { stop: { target: 'idle' } }
    }
  }
});

const provided = machine.provide({ actors: { chargeCard } });

On this page