This page provides a comprehensive reference of all breaking changes introduced in XState v5. For a guided migration, see the v4 to v5 migration guide .
API Changes
interpret() → createActor()
interpret() has been completely removed. Use createActor() instead.
-import { interpret } from 'xstate';
+import { createActor } from 'xstate';
-const service = interpret(machine).start();
+const actor = createActor(machine).start();
String Events No Longer Supported
actorRef.send('EVENT') will throw an error. Events must be objects.
-actorRef.send('TOGGLE');
+actorRef.send({ type: 'TOGGLE' });
-actorRef.send('EVENT', { data: 'value' });
+actorRef.send({ type: 'EVENT', data: 'value' });
schema → types
The schema property is no longer recognized. Use types instead.
const machine = createMachine({
- schema: {
- context: {} as { count: number }
- },
+ types: {} as {
+ context: { count: number };
+ },
context: { count: 0 }
});
Context Property Required When Types Specified
If you define context types, you must provide an initial context value.
// ❌ Will cause TypeScript error
createMachine ({
types: {} as { context : { count : number } }
});
// ✅ Correct
createMachine ({
types: {} as { context : { count : number } },
context: { count: 0 }
});
data → output
The data property on final states has been removed. Use output instead.
states: {
success: {
type: 'final',
- data: { result: 42 }
+ output: { result: 42 }
}
}
external → reenter
The external property on transitions has been renamed to reenter.
on: {
EVENT: {
target: 'sameState',
- external: true
+ reenter: true
}
}
in Property Removed
The in transition property has been removed. Use stateIn() guard instead.
+import { stateIn } from 'xstate/guards';
on: {
EVENT: {
target: 'target',
- in: '#someState'
+ guard: stateIn('#someState')
}
}
autoForward Removed
Auto-forwarding events is no longer supported. Explicitly forward events using sendTo().
invoke: {
id: 'child',
src: childMachine,
- autoForward: true
},
+on: {
+ FORWARD_THIS: {
+ actions: sendTo('child', (_, event) => event)
+ }
+}
machine.initialState Removed
machine.initialState has been removed. Use machine.getInitialState() instead.
-const initialState = machine.initialState;
+const initialState = machine.getInitialState();
machine.withConfig() → machine.provide()
withConfig() has been renamed to provide().
-const configuredMachine = machine.withConfig({
+const configuredMachine = machine.provide({
actions: { /* ... */ }
});
machine.transition() Context Parameter Removed
The third parameter (context) has been removed from machine.transition().
-machine.transition('green', { type: 'TIMER' }, { elapsed: 100 });
+machine.transition(
+ machine.resolveState({ value: 'green', context: { elapsed: 100 } }),
+ { type: 'TIMER' }
+);
State/Snapshot Changes
State Properties Removed
The following properties have been removed from state/snapshot objects:
state.events - No replacement
state.nextEvents - No replacement
state.toStrings() - No replacement
state.activities - Activities are now part of invoke declarations
State Restoration API Changed
Restoring state now uses the snapshot option instead of passing state to start().
-interpret(machine).start(persistedState);
+createActor(machine, { snapshot: persistedSnapshot }).start();
Get persisted state:
-const state = actor.getSnapshot();
+const persistedSnapshot = actor.getPersistedSnapshot();
Restored State No Longer Contains Actions
Restored snapshots no longer include actions, as they’re assumed to have been executed.
If you need to replay actions, use event sourcing instead.
Actor/Service Changes
Removed Actor Methods
The following methods have been removed from actor references:
Removed Replacement actorRef.onEvent()actorRef.subscribe()actorRef.onSend()actorRef.subscribe()actorRef.onChange()actorRef.subscribe()actorRef.onStop()actorRef.subscribe({ complete() {} })actorRef.sender()actorRef.send()
send() No Longer Returns Next State
actorRef.send() is now void (fire-and-forget). It no longer returns the next state.
-const nextState = actorRef.send({ type: 'EVENT' });
+actorRef.send({ type: 'EVENT' });
+const nextState = actorRef.getSnapshot();
Callback Actors Cannot Return Promises
Returning promises from callback actors is no longer supported. Only cleanup functions (or undefined) can be returned.
fromCallback(({ sendBack }) => {
- return new Promise((resolve) => {
- // ...
- });
+ const cleanup = () => {
+ // cleanup logic
+ };
+ return cleanup;
});
Behavior Changes
assign() Actions Execute in Order
assign() actions are no longer automatically prioritized. They execute in the order defined.
// In v5, these execute sequentially
entry : [
assign ({ count : ({ context }) => context . count + 1 }),
assign ({ doubled : ({ context }) => context . count * 2 }) // Uses updated count
]
To maintain v4 behavior, define all assign() actions before other actions.
Eventless Transitions Propagate Original Event
Actions following eventless transitions now receive the original event, not a null event { type: '' }.
states : {
a : {
on : { SOME_EVENT : 'b' }
},
b : {
always : 'c'
},
c : {
entry : ({ event }) => {
// v4: event.type === ''
// v5: event.type === 'SOME_EVENT'
}
}
}
No Re-entering on Internal Transitions
Atomic and parallel states are no longer re-entered on internal transitions by default.
Use reenter: true to get the previous behavior:
on : {
SELF_TRANSITION : {
target : 'sameState' ,
reenter : true // Explicitly re-enter
}
}
Compound States Must Specify initial
Compound state nodes without an initial property will now throw an error.
// ❌ Will throw error
states : {
parent : {
states : {
child1 : {},
child2 : {}
}
}
}
// ✅ Correct
states : {
parent : {
initial : 'child1' ,
states : {
child1 : {},
child2 : {}
}
}
}
Delayed Event IDs No Longer Auto-Generated
Delayed events no longer derive IDs from event types. You must provide explicit IDs when using cancel().
-entry: raise({ type: 'TIMEOUT' }, { delay: 1000 });
-exit: cancel('TIMEOUT');
+entry: raise({ type: 'TIMEOUT' }, { delay: 1000, id: 'timeout' });
+exit: cancel('timeout');
Type System Changes
Context Must Be an Object
Machine context is now restricted to Record<string, any>. Primitive values are not allowed.
// ❌ Not allowed
createMachine ({
context: 'some string'
});
// ✅ Use an object
createMachine ({
context: { value: 'some string' }
});
If context is undefined, it defaults to {}.
Action Creators Return Functions
All built-in action creators now return functions. Their exact shape is an implementation detail.
import { assign } from 'xstate' ;
// Don't rely on the shape, just pass them to actions
const increment = assign ({ count : ({ context }) => context . count + 1 });
tsTypes → types.typegen
The tsTypes property has been moved to types.typegen.
const machine = createMachine({
- tsTypes: {},
+ types: {} as {
+ typegen: {};
+ context: { /* ... */ };
+ }
});
Other Changes
Target Resolution from Root
Targeting sibling states from the root now requires explicit relative syntax.
createMachine({
initial: 'a',
states: { a: {}, b: {} },
on: {
- GO_TO_B: 'b'
+ GO_TO_B: '.b'
}
});
execute Option Removed
The execute option for interpreted services has been removed.
Don’t hardcode implementation details in the base machine. Use machine.provide() to extend actions instead.
Redux DevTools is no longer the default integration.
import { createActor } from 'xstate' ;
import { createReduxDevTools } from 'xstate/devTools/redux' ;
const actor = createActor ( machine , {
devTools: createReduxDevTools ({ /* options */ })
});
Default dev tools attach to window.__xstate__:
const actor = createActor ( machine , {
devTools: true
});
Context Function Removed
The context property no longer accepts a function for determining initial context.
Use the input parameter in createActor() instead:
const machine = createMachine ({
context : ({ input }) => ({
value: input . initialValue
})
});
const actor = createActor ( machine , {
input: { initialValue: 42 }
});
State Node Getters Removed
Support for getters as transition targets has been removed.
Use state node IDs or relative keys instead.
Machine() No Longer Accepts Context as Third Argument
The Machine() and createMachine() functions no longer support a third argument for context.
-const machine = createMachine(config, options, context);
+const machine = createMachine({ ...config, context });
Migration Resources
Migration Guide Step-by-step guide to migrating from v4 to v5
Getting Help Get help with your migration on Discord or GitHub