Finite State Machines and Statecharts for the Modern Web.
XState is a state management library that implements finite state machines, statecharts, and the actor model for JavaScript and TypeScript applications. With over 3 million weekly downloads, it provides a formal approach to managing application logic through explicitly defined states and transitions, making complex workflows predictable and maintainable. Unlike traditional state management solutions, XState treats state as a finite set of named conditions rather than an arbitrary data container, preventing impossible state combinations at the type level.
The library is framework-agnostic with zero dependencies, running in any JavaScript environment including React, Vue, Svelte, Node.js, Deno, and serverless platforms. XState adheres to the SCXML specification and provides visual tooling through Stately Studio, allowing developers to design, test, and collaborate on state machines using interactive diagrams. This visual representation serves as living documentation that stays synchronized with the actual implementation.
XState is particularly valuable for applications with complex user flows, multi-step forms, authentication processes, or coordinated async operations. Companies like Gatsby use it for build orchestration, while others deploy it for Electron apps and VSCode extensions. The event-driven architecture encourages separation of concerns: your UI sends events, the machine handles transitions, and components subscribe to relevant state changes. Version 5 brings improved TypeScript inference, simplified APIs, and enhanced actor model capabilities for building distributed systems within your application.
import { createMachine, createActor, assign } from 'xstate';
// Define a traffic light machine with timer-based transitions
const trafficLightMachine = createMachine({
id: 'trafficLight',
initial: 'green',
context: {
crosswalkRequested: false,
violations: 0
},
states: {
green: {
on: {
TIMER: 'yellow',
REQUEST_CROSSWALK: {
actions: assign({ crosswalkRequested: true })
}
},
after: {
30000: 'yellow' // Auto-transition after 30s
}
},
yellow: {
on: {
TIMER: 'red'
},
after: {
3000: 'red'
}
},
red: {
entry: assign({ crosswalkRequested: false }),
on: {
TIMER: 'green',
VIOLATION: {
actions: assign({
violations: ({ context }) => context.violations + 1
})
}
},
after: {
45000: 'green'
}
}
}
});
// Create and start the actor
const actor = createActor(trafficLightMachine);
actor.subscribe((snapshot) => {
console.log('Current state:', snapshot.value);
console.log('Violations:', snapshot.context.violations);
});
actor.start();
// Send events
actor.send({ type: 'REQUEST_CROSSWALK' });
actor.send({ type: 'TIMER' }); // green -> yellow
actor.send({ type: 'TIMER' }); // yellow -> red
actor.send({ type: 'VIOLATION' }); // Increment violations
// Check current state
console.log(actor.getSnapshot().matches('red')); // trueMulti-step form wizards: Model each form step as a distinct state with explicit transitions for next/previous/skip actions. XState ensures users can't submit incomplete data or navigate to invalid steps, while maintaining form context across the entire flow.
Authentication flows: Orchestrate login, registration, password reset, and MFA verification as a single state machine. Handle token refresh, session expiration, and logout across multiple tabs while preventing race conditions between authentication states.
File upload workflows: Manage the complete lifecycle from file selection through validation, upload progress, retry logic, success confirmation, and error handling. The state machine ensures proper cleanup on cancellation and prevents simultaneous conflicting operations.
Backend process orchestration: Coordinate long-running serverless functions, database transactions, and external API calls with built-in retry strategies and compensation logic. Use waitFor to pause execution until specific states are reached in async environments.
UI component behavior: Replace boolean flags like isLoading, isError, and isSuccess with explicit states that make impossible combinations unreachable. A component can't simultaneously display loading spinners and error messages because the machine structure prevents it.
npm install xstatepnpm add xstatebun add xstate