Documentation Index Fetch the complete documentation index at: https://mintlify.com/statelyai/xstate/llms.txt
Use this file to discover all available pages before exploring further.
Configures and creates a type-safe state machine builder with predefined implementations for actions, guards, actors, and delays.
The setup() function is the recommended way to create state machines in XState v5, as it provides excellent TypeScript type inference and allows you to define reusable implementations.
Signature
function setup <
TContext extends MachineContext ,
TEvent extends AnyEventObject ,
TActors extends Record < string , UnknownActorLogic >,
TChildrenMap extends Record < string , string >,
TActions extends Record < string , ParameterizedObject [ 'params' ] | undefined >,
TGuards extends Record < string , ParameterizedObject [ 'params' ] | undefined >,
TDelay extends string ,
TTag extends string ,
TInput ,
TOutput extends NonReducibleUnknown ,
TEmitted extends EventObject ,
TMeta extends MetaObject
>({
types ,
actors ,
actions ,
guards ,
delays
}) : SetupReturn <...>
Parameters
Configuration object for the machine setup. Type definitions for TypeScript inference. This is a compile-time only property. types : {} as {
context : { count : number };
events : { type : 'INCREMENT' } | { type : 'DECREMENT' };
input : { initialCount : number };
output : number ;
}
actors
Record<string, ActorLogic>
A map of actor logic creators that can be invoked or spawned. actors : {
fetchUser : fromPromise ( async ({ input }) => {
const response = await fetch ( `/api/users/ ${ input . userId } ` );
return response . json ();
})
}
actions
Record<string, ActionFunction>
A map of action implementations that can be referenced by name. actions : {
logMessage : ({ context , event }) => {
console . log ( context . message , event );
}
}
guards
Record<string, GuardPredicate>
A map of guard (condition) implementations that can be referenced by name. guards : {
isPositive : ({ context }) => context . count > 0 ,
isEven : ({ context }) => context . count % 2 === 0
}
delays
Record<string, DelayConfig>
A map of delay values or functions for delayed transitions and actions. delays : {
SHORT : 1000 ,
LONG : ({ context }) => context . timeout
}
Returns
An object with methods for creating machines and type-safe helpers. Creates a state machine with the configured types and implementations. createMachine ( config : MachineConfig ): StateMachine
Returns a new setup with additional actions, guards, and delays merged with existing ones. extend ({ actions?, guards?, delays? }): SetupReturn
Type-safe version of the assign action creator.
Type-safe version of the sendTo action creator.
Type-safe version of the raise action creator.
Type-safe version of the log action creator.
Type-safe version of the cancel action creator.
Type-safe version of the stopChild action creator.
Type-safe version of the enqueueActions action creator.
Type-safe version of the emit action creator.
Type-safe version of the spawnChild action creator.
Creates a type-safe state config that can be reused in multiple machines.
Creates a type-safe action implementation.
Examples
Basic setup with types
import { setup , createActor } from 'xstate' ;
const counterMachine = setup ({
types: {} as {
context : { count : number };
events : { type : 'INCREMENT' } | { type : 'DECREMENT' };
}
}). createMachine ({
initial: 'active' ,
context: { count: 0 },
states: {
active: {
on: {
INCREMENT: {
actions: assign ({
count : ({ context }) => context . count + 1
})
},
DECREMENT: {
actions: assign ({
count : ({ context }) => context . count - 1
})
}
}
}
}
});
Setup with actions and guards
import { setup } from 'xstate' ;
const feedbackMachine = setup ({
types: {} as {
context : { feedback : string ; retries : number };
events :
| { type : 'SUBMIT' }
| { type : 'RETRY' }
| { type : 'CANCEL' };
},
actions: {
logSubmission : ({ context }) => {
console . log ( 'Submitting feedback:' , context . feedback );
},
incrementRetries: assign ({
retries : ({ context }) => context . retries + 1
}),
clearRetries: assign ({
retries: 0
})
},
guards: {
canRetry : ({ context }) => context . retries < 3 ,
hasValidFeedback : ({ context }) => context . feedback . length > 0
}
}). createMachine ({
initial: 'editing' ,
context: { feedback: '' , retries: 0 },
states: {
editing: {
on: {
SUBMIT: {
guard: 'hasValidFeedback' ,
target: 'submitting'
}
}
},
submitting: {
entry: 'logSubmission' ,
on: {
SUCCESS: {
target: 'success' ,
actions: 'clearRetries'
},
ERROR: {
guard: 'canRetry' ,
target: 'editing' ,
actions: 'incrementRetries'
}
}
},
success: {
type: 'final'
}
}
});
Setup with actors
import { setup , fromPromise } from 'xstate' ;
const userMachine = setup ({
types: {} as {
context : { user : User | null };
events : { type : 'FETCH' ; userId : string };
},
actors: {
fetchUser: fromPromise ( async ({ input } : { input : { userId : string } }) => {
const response = await fetch ( `/api/users/ ${ input . userId } ` );
return response . json ();
})
}
}). createMachine ({
initial: 'idle' ,
context: { user: null },
states: {
idle: {
on: {
FETCH: 'loading'
}
},
loading: {
invoke: {
src: 'fetchUser' ,
input : ({ event }) => ({ userId: event . userId }),
onDone: {
target: 'success' ,
actions: assign ({
user : ({ event }) => event . output
})
},
onError: 'failure'
}
},
success: {},
failure: {}
}
});
Setup with delays
import { setup } from 'xstate' ;
const timeoutMachine = setup ({
types: {} as {
context : { timeout : number };
events : { type : 'START' } | { type : 'RESET' };
},
delays: {
SHORT: 1000 ,
LONG: 5000 ,
DYNAMIC : ({ context }) => context . timeout
}
}). createMachine ({
initial: 'idle' ,
context: { timeout: 3000 },
states: {
idle: {
on: {
START: 'waiting'
}
},
waiting: {
after: {
DYNAMIC: 'done'
},
on: {
RESET: 'idle'
}
},
done: {
type: 'final'
}
}
});
Using extend
import { setup } from 'xstate' ;
const baseSetup = setup ({
types: {} as {
context : { count : number };
events : { type : 'INCREMENT' };
},
actions: {
logCount : ({ context }) => {
console . log ( context . count );
}
}
});
const extendedSetup = baseSetup . extend ({
actions: {
logDouble : ({ context }) => {
console . log ( context . count * 2 );
}
}
});
const machine = extendedSetup . createMachine ({
initial: 'active' ,
context: { count: 0 },
states: {
active: {
entry: [ 'logCount' , 'logDouble' ]
}
}
});
import { setup } from 'xstate' ;
const calculatorMachine = setup ({
types: {} as {
context : { total : number };
input : { initialValue : number };
output : number ;
events : { type : 'ADD' ; value : number };
}
}). createMachine ({
initial: 'calculating' ,
context : ({ input }) => ({
total: input . initialValue
}),
states: {
calculating: {
on: {
ADD: {
actions: assign ({
total : ({ context , event }) => context . total + event . value
})
},
FINISH: 'done'
}
},
done: {
type: 'final'
}
},
output : ({ context }) => context . total
});
const actor = createActor ( calculatorMachine , {
input: { initialValue: 10 }
});
actor . start ();
actor . send ({ type: 'ADD' , value: 5 });
Notes
The types property is used solely for TypeScript type inference and has no runtime behavior
Actions, guards, actors, and delays defined in setup can be referenced by their string keys in the machine configuration
Using setup() is recommended over passing implementations as a second argument to createMachine()
The extend() method allows for composition and reuse of configurations
See also