Skip to content
Version: XState v4

Internal and external transitions

Transitions in statecharts can be one of two types: internal or external. External transitions are transitions that leave the machine’s current state node; the “source” state node on which the transition is defined.

In the example below, a -> FOO -> b is an external transition.

import { createMachine } from 'xstate';

createMachine({
initial: 'a',
states: {
a: {
on: {
FOO: 'b',
},
},
b: {},
},
});

The transition leaves the a state and goes to the b state, making it an external transition.

Internal transitions do not leave the current state. For example, self-transitions are internal transitions:

import { createMachine } from 'xstate';

createMachine(
{
initial: 'a',
states: {
a: {
on: {
FOO: {
actions: 'sayHello',
},
},
},
},
},
{
actions: {
sayHello: () => {
console.log('Hello!');
},
},
},
);

The FOO transition never leaves the a state, which makes it an internal transition.

However, you can force an internal transition to become an external transition. For self-transitions, you can specify the target on the transition to force it to be an external transition:

import { createMachine } from 'xstate';

createMachine(
{
initial: 'a',
states: {
a: {
entry: ['logThatThisStateWasEntered'],
on: {
FOO: {
target: 'a',
actions: 'sayHello',
},
},
},
},
},
{
actions: {
sayHello: () => {
console.log('Hello!');
},
logThatThisStateWasEntered: () => {
console.log('A was entered!');
},
},
},
);

When target is a, the transition becomes external, which means the node is exited and re-entered and the entry and exit actions will be re-fired. You can use this trick to re-run delays, restart services and it is also useful in parent and child states.