Machine configuration
Reference for the top-level state machine configuration.
XState v6 is in alpha
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
| Property | Type | Description |
|---|---|---|
id | string | Stable identifier for the root state node. Used by #id targets and in state node ids. |
description | string | Human-readable description. |
context | value or ({ input, spawn, actors, self }) => value | Initial context. Required when the context type is not never. |
initial | string or { target, input } | Initial child state. The object form passes state input. |
states | Record<string, StateNodeConfig> | Child state nodes. |
on | Record<EventType, TransitionConfigOrTarget> | Transitions available in every child state. |
entry | transition function or named action | Runs when the machine starts. |
exit | transition function or named action | Runs when the machine stops. |
invoke | InvokeConfig or InvokeConfig[] | Actor logic invoked for the machine's lifetime. |
always | transition | Eventless transition checked after every microstep. |
after | Record<delay, transition> | Delayed transitions. |
timeout | number, delay name, or function | Deadline for the machine. See timeouts. |
onTimeout | transition | Taken when timeout elapses. Required with timeout. |
onDone | transition | Taken when a final child state is reached. See final states. |
onError | transition | Taken on xstate.error.* raised below this node. See errors. |
output | value or ({ context, event }) => value | Output produced on completion. |
schemas | { context, events, emitted, input, output, meta, tags, children, actions, guards } | Standard Schema definitions. See TypeScript. |
internalEvents | readonly EventType[] | Events the machine may raise but no one may send in. See internal events. |
actions | Record<string, (params, args) => void> | Named action sources. See setup and provide. |
guards | Record<string, (params, args) => boolean> | Named guard sources. See guards. |
actors | Record<string, ActorLogic> | Named actor logic sources. See invoke. |
delays | Record<string, number | (args) => number> | Named delay sources. See delays. |
version | string | The machine's own version, stamped onto persisted snapshots. See persistence. |
migrate | (persistedSnapshot, fromVersion) => unknown | Upgrades a persisted snapshot whose version does not match. Restoring a mismatched snapshot without it throws. |
meta | object | Metadata for the root state node. Must match schemas.meta. |
tags | string[] | 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.
| Property | Type | Description |
|---|---|---|
initial | string or { target, input } | Initial child state. The object form passes state input. |
states | Record<string, StateNodeConfig> | Child state nodes. |
type | 'atomic' | 'compound' | 'parallel' | 'final' | 'history' | Node kind. See parallel states, final states and history states. |
history | 'shallow' | 'deep' | boolean | History kind for a history state node. |
target | string | string[] | Default target of a history state node. |
on | Record<EventType, TransitionConfigOrTarget> | Event transitions. |
entry | transition function or named action | Runs on entering this state. |
exit | transition function or named action | Runs on exiting this state. |
invoke | InvokeConfig or InvokeConfig[] | Actors started on entry and stopped on exit. |
after | Record<delay, transition> | Delayed transitions scheduled on entry. |
timeout / onTimeout | see above | State deadline and its transition. See timeouts. |
always | transition | Eventless transition taken while this state is active. |
onDone | transition | Taken when a final child state is reached. |
onError | transition | Taken on an error raised at or below this state. |
output | value or mapper | Output of a final state node. |
id | string | Unique id, targetable as #id. |
route | RouteConfig | Enables { type: 'xstate.route', to: '#id' }. Requires an explicit id. See route states. |
meta | object | Metadata read with snapshot.getMeta(). See states. |
tags | string[] | Tags read with snapshot.hasTag(...). |
description | string | Human-readable description. |
order | number | Document 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 } });