Skip to content

yay-machine

a modern, simple, lightweight, zero-dependency, TypeScript state-machine library

yay-machine borrows the best ideas from other JS/TypeScript state-machine and state-management libraries.

It will feel familiar to XState users, with features including:

  • JSON config
  • state-data (context / extended-state / dynamic state)
  • conditional transitions (guards)
  • immediate (always) transitions
  • event handling in specific-state or any-state
  • similar creation and lifecycle API

And yay-machine brings new ideas of its own:

  • states are types (think: interface). They are an object with a name and any associated data. Different states may have different associated data
  • side-effects are all you need for sync/async interactions with the current machine and outside world

We prefer contemporary accessible language, to traditional academic terms.

yay-machine has only a handful of concepts and the API is minimal

  • states
  • events
  • transitions
  • side-effects

These features can be combined to model just about anything.

It should be quick to learn, and have a minimal ongoing cost-of-ownership.

yay-machine is a tiny package and won’t bloat your app bundles.

yay-machine bundlephobia stats

Minimal implementation means minimal overhead and you can trust yay-machine with your high-performance workloads.

yay-machine vs XState: all benchmarks UI: sign-up form, form session (38 events): yay-machine 1.30M events/s, XState 162k events/s; 8.1× faster. Event stream: long-lived connection, replay 1,000-event trace: yay-machine 5.24M events/s, XState 283k events/s; 19× faster. Fleet: 1,000 live connections, 1 event to each of 1,000 instances: yay-machine 2.18M events/s, XState 192k events/s; 11× faster. Login request, login success + logout: yay-machine 271k requests/s, XState 18.9k requests/s; 14× faster. Login request, login rejected + retry: yay-machine 320k requests/s, XState 18.0k requests/s; 18× faster. Memory per live instance, started, idle (disconnected): yay-machine 1.23 KiB per instance, XState 2.69 KiB per instance; 2.2× less memory. Memory per live instance, connected (with heartbeat resource): yay-machine 1.33 KiB per instance, XState 3.94 KiB per instance; 3.0× less memory. Toggle, send TOGGLE: yay-machine 3.53M events/s, XState 164k events/s; 22× faster. Counter, INCREMENT + DECREMENT (guards pass): yay-machine 1.35M events/s, XState 254k events/s; 5.3× faster. Counter, INCREMENT beyond max (guard rejects): yay-machine 9.29M events/s, XState 828k events/s; 11× faster. Guards, 1st guard matches: yay-machine 2.08M events/s, XState 268k events/s; 7.8× faster. Guards, 3rd guard matches: yay-machine 1.79M events/s, XState 287k events/s; 6.3× faster. Guards, default (5th) matches: yay-machine 1.93M events/s, XState 236k events/s; 8.2× faster. Immediate transitions, routes via 1st branch: yay-machine 1.61M events/s, XState 91.0k events/s; 18× faster. Immediate transitions, routes via last branch: yay-machine 1.27M events/s, XState 89.3k events/s; 14× faster. Event resolution, handled by current state: yay-machine 2.00M events/s, XState 249k events/s; 8.0× faster. Event resolution, falls through to machine-level: yay-machine 2.05M events/s, XState 221k events/s; 9.3× faster. Event resolution, not handled (ignored): yay-machine 28.5M events/s, XState 670k events/s; 43× faster. State effects, entry + exit actions: yay-machine 2.01M events/s, XState 129k events/s; 16× faster. State effects, state-scoped resource + cleanup: yay-machine 1.96M events/s, XState 63.9k events/s; 31× faster. Lifecycle, define a 5-state machine: yay-machine 593k definitions/s, XState 37.4k definitions/s; 16× faster. Lifecycle, create + start + stop: yay-machine 1.18M lifecycles/s, XState 92.7k lifecycles/s; 13× faster. Lifecycle, ... with machine-scoped resource: yay-machine 1.09M lifecycles/s, XState 31.1k lifecycles/s; 35× faster. Batch of short-lived instances, batch of 10: yay-machine 870k lifecycles/s, XState 50.3k lifecycles/s; 17× faster. yay-machine vs XState: all benchmarks How many times faster (or leaner) yay-machine is than XState for each benchmark. Log scale · 1× = parity · bars left of 1× would mean XState is ahead 0.5×1×2×5×10×20×50×REALISTIC WORKLOADSUI: sign-up formform session (38 events)8.1×Event stream: long-lived connectionreplay 1,000-event trace19×Fleet: 1,000 live connections1 event to each of 1,000 instances11×Login requestlogin success + logout14×Login requestlogin rejected + retry18×Memory per live instancestarted, idle (disconnected)2.2× less memoryMemory per live instanceconnected (with heartbeat resource)3.0× less memoryFEATURE MICRO-BENCHMARKSTogglesend TOGGLE22×CounterINCREMENT + DECREMENT (guards pass)5.3×CounterINCREMENT beyond max (guard rejects)11×Guards1st guard matches7.8×Guards3rd guard matches6.3×Guardsdefault (5th) matches8.2×Immediate transitionsroutes via 1st branch18×Immediate transitionsroutes via last branch14×Event resolutionhandled by current state8.0×Event resolutionfalls through to machine-level9.3×Event resolutionnot handled (ignored)43×State effectsentry + exit actions16×State effectsstate-scoped resource + cleanup31×Lifecycledefine a 5-state machine16×Lifecyclecreate + start + stop13×Lifecycle... with machine-scoped resource35×Batch of short-lived instancesbatch of 1017× yay-machine v1.5.0+297 (4179cf1) · xstate 5.33.3 · Bun 1.4.3 · 2026-11-09 11th Gen Intel(R) Core(TM) i7-1185G7 @ 3.00GHz, 8 cores, 8 GB · Linux (WSL2) (x64)

See Benchmarks for what each benchmark measures, and how.

The core yay-machine state-machine library has zero production dependencies.

It won’t bloat your node_modules/ and you won’t have to worry about having to patch some security vulnerability or compatibility issue in a 3rd-party package that yay-machine depends on.

We ❤️ TypeScript and want the best experience for TypeScript developers with state-machines.

Each state in yay-machine is a type, giving you more compile-time confidence.

Examples

Checkout out our various examples to demonstrate solving problems with with yay-machine

Reference docs

Get detailed explanations of concepts and application in the reference docs