# Technical Documentation: statelyai/xstate

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/statelyai/xstate)

### Overview (`README.md`)

<p align="center">
  <br />

  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/statelyai/public-assets/main/logos/xstate-logo-white-nobg.svg">
    <img alt="XState logotype" src="https://raw.githubusercontent.com/statelyai/public-assets/main/logos/xstate-logo-black-nobg.svg" width="200">
  </picture>
  <br />
    <strong>Actor-based state management & orchestration for complex app logic.</strong> <a href="https://stately.ai/docs">→ Documentation</a>
  <br />
  <br />
</p>

XState is a state management and orchestration solution for JavaScript and TypeScript apps. It has _zero_ dependencies, and is useful for frontend and backend application logic.

It uses event-driven programming, state machines, statecharts, and the actor model to handle complex logic in predictable, robust, and visual ways. XState provides a powerful and flexible way to manage application and workflow state by allowing developers to model logic as actors and state machines.

### ✨ Create state machines visually in Stately Studio → [state.new](https://state.new)

---

📖 [Read the documentation](https://stately.ai/docs)

➡️ [Create state machines with the Stately Editor](https://stately.ai/editor)

🖥 [Download our VS Code extension](https://marketplace.visualstudio.com/items?itemName=statelyai.stately-vscode)

📑 Inspired by the [SCXML specification](https://www.w3.org/TR/scxml/)

💬 Chat on the [Stately Discord Community](https://discord.gg/xstate)

✍️ Browse through the many [XState examples](https://github.com/statelyai/xstate/tree/main/examples)

## Which package should I use?

Pick based on what you need:



- **[`@xstate/store`](#xstate-store)**: simple event-based state management and reactive atoms, with great TypeScript inference, similar in spirit to Redux/Zustand. Start here if you just need a store.
- **[`xstate`](#super-quick-start)**: state machines, statecharts, actors, effects, and orchestration for complex app logic.

They work great together, but you don't need one to use the other.

## Sponsors

Special thanks to the sponsors who support this open-source project:

<img src="https://opencollective.com/xstate/tiers/backer/badge.svg?label=sponsors&color=brightgreen" />

## Templates

Get started by forking one of these templates on CodeSandbox:

<table>
<thead>
<tr><th>Template</th><th></th></tr>
</thead>
<tbody>

<tr>
<td>

[🤖 XState Template (CodeSandbox)](https://codesandbox.io/p/devbox/github/statelyai/xstate/tree/main/templates/vanilla-ts)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/templates/vanilla-ts?file=%2Fsrc%2FfeedbackMachine.ts)

</td>
<td>

- XState v5
- TypeScript
- _No framework_

</td>
</tr>

<tr>
<td>

[⚛️ XState + React Template (CodeSandbox)](https://codesandbox.io/p/devbox/github/statelyai/xstate/tree/main/templates/react-ts)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/templates/react-ts?file=%2Fsrc%2FfeedbackMachine.ts)

</td>
<td>

- [React](https://react.dev/)
- XState v5
- TypeScript

</td>
</tr>

<tr>
<td>

[💚 XState + Vue Template (CodeSandbox)](https://codesandbox.io/p/devbox/github/statelyai/xstate/tree/main/templates/vue-ts)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/templates/vue-ts?file=%2Fsrc%2FfeedbackMachine.ts)

</td>
<td>

- [Vue](https://vuejs.org/)
- XState v5
- TypeScript

</td>
</tr>

<tr>
<td>

[🧡 XState + Svelte Template (CodeSandbox)](https://codesandbox.io/p/devbox/github/statelyai/xstate/tree/main/templates/svelte-ts)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/templates/svelte-ts?file=%2Fsrc%2FfeedbackMachine.ts)

</td>
<td>

- [Svelte](https://svelte.dev/)
- XState v5
- TypeScript

</td>
</tr>

</tbody>
</table>

## Super quick start

```bash
npm install xstate
```

```ts
import { createMachine, createActor, assign } from 'xstate';

// State machine
const toggleMachine = createMachine({
  id: 'toggle',
  initial: 'inactive',
  context: {
    count: 0
  },
  states: {
    inactive: {
      on: {
        TOGGLE: { target: 'active' }
      }
    },
    active: {
      entry: assign({ count: ({ context }) => context.count + 1 }),
      on: {
        TOGGLE: { target: 'inactive' }
      }
    }
  }
});

// Actor (instance of the machine logic, like a store)
const toggleActor = createActor(toggleMachine);
toggleActor.subscribe((state) => console.log(state.value, state.context));
toggleActor.start();
// => logs 'inactive', { count: 0 }

toggleActor.send({ type: 'TOGGLE' });
// => logs 'active', { count: 1 }

toggleActor.send({ type: 'TOGGLE' });
// => logs 'inactive', { count: 1 }
```

---

<a id="xstate-store"></a>

## `@xstate/store`: simple state management

Not every app needs all the features of state machines and statecharts. **[`@xstate/store`](https://github.com/statelyai/xstate/tree/main/packages/xstate-store)** is a separate, extremely small event-based store with first-class TypeScript inference; similar to Redux or Zustand, but with less boilerplate.

Use it on its own, or graduate to full XState machines when your logic gets more complex.

```bash
npm install @xstate/store
```

```ts
import { createStore } from '@xstate/store';

const donutStore = createStore({
  context: {
    donuts: 0,
    favoriteFlavor: 'chocolate'
  },
  on: {
    addDonut: (context) => ({ ...context, donuts: context.donuts + 1 }),
    changeFlavor: (context, event: { flavor: string }) => ({
      ...context,
      favoriteFlavor: event.flavor
    }),
    eatAllDonuts: (context) => ({ ...context, donuts: 0 })
  }
});

donutStore.subscribe((snapshot) => {
  console.log(snapshot.context);
});

donutStore.send({ type: 'addDonut' });
// => { donuts: 1, favoriteFlavor: 'chocolate' }

donutStore.send({ type: 'changeFlavor', flavor: 'strawberry' });
// => { donuts: 1, favoriteFlavor: 'strawberry' }
```

📖 See the [`@xstate/store` README](https://github.com/statelyai/xstate/tree/main/packages/xstate-store) for React/Solid bindings, selectors, and more.

---

## [Stately Studio](https://stately.ai)

- Visually create, edit, and collaborate on state machines
- Export to many formats, including XState v5
- Test path & documentation autogeneration
- Deploy to Stately Sky
- Generate & modify machines with Stately AI

<a href="https://stately.ai/registry/new?ref=github" title="Stately Studio">
  <img src="https://github.com/statelyai/xstate/assets/1093738/74ed9cbc-b824-4ed7-a16d-f104947af8a7" alt="XState Viz" width="800" />
</a>

**[state.new](https://stately.ai/registry/new?ref=github)**

## Why?

Statecharts are a formalism for modeling stateful, reactive systems. This is useful for declaratively describing the _behavior_ of your application, from the individual components to the overall application logic.

Read [📽 the slides](http://slides.com/davidkpiano/finite-state-machines) ([🎥 video](https://www.youtube.com/watch?v=VU1NKX6Qkxc)) or check out these resources for learning about the importance of finite state machines and statecharts in user interfaces:

- [Statecharts - A Visual Formalism for Complex Systems](https://www.sciencedirect.com/science/article/pii/0167642387900359/pdf) by David Harel
- [The World of Statecharts](https://statecharts.github.io/) by Erik Mogensen

## Packages



| Package                                                                                     | Description                                                                                                                  |
| ------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| 🤖 `xstate`                                                                                 | Core finite state machine and statecharts library + interpreter, including graph traversal and model-based testing utilities |
| [🏪 `@xstate/store`](https://github.com/statelyai/xstate/tree/main/packages/xstate-store)   | Simple event-based state management and reactive atoms — standalone, works with or without `xstate`                                      |
| [⚛️ `@xstate/react`](https://github.com/statelyai/xstate/tree/main/packages/xstate-react)   | React hooks and utilities for using XState in React applications                                                             |
| [💚 `@xstate/vue`](https://github.com/statelyai/xstate/tree/main/packages/xstate-vue)       | Vue composition functions and utilities for using XState in Vue applications                                                 |
| [🎷 `@xstate/svelte`](https://github.com/statelyai/xstate/tree/main/packages/xstate-svelte) | Svelte utilities for using XState in Svelte applications                                                                     |
| [🥏 `@xstate/solid`](https://github.com/statelyai/xstate/tree/main/packages/xstate-solid)   | Solid hooks and utilities for using XState in Solid applications                                                             |
| [🔍 `@statelyai/inspect`](https://github.com/statelyai/inspect)                             | Inspection utilities for XState                                                                                              |

## Finite State Machines

<table>
<thead><tr><th>Code</th><th>Statechart</th></tr></thead>
<tbody>
<tr>
<td>

```js
import { createMachine, createActor } from 'xstate';

const lightMachine = createMachine({
  id: 'light',
  initial: 'green',
  states: {
    green: {
      on: {
        TIMER: 'yellow'
      }
    },
    yellow: {
      on: {
        TIMER: 'red'
      }
    },
    red: {
      on: {
        TIMER: 'green'
      }
    }
  }
});

const actor = createActor(lightMachine);

actor.subscribe((state) => {
  console.log(state.value);
});

actor.start();
// logs 'green'

actor.send({ type: 'TIMER' });
// logs 'yellow'
```

</td>
<td>

<a href="https://stately.ai/registry/editor/fa443471-b416-4014-8e6f-12417863e4d4?mode=design&machineId=27e86036-f2f7-40f1-9d1e-66ce6e1accc0" title="Finite states">
  <img src="https://github.com/statelyai/xstate/assets/1093738/36d4b6b5-e3d0-4c19-9f41-2e3425ceac88" alt="Finite states" width="400" />
  <br />
  Open in Stately Studio
</a>
<br />

</td>
</tbody>
</table>

## Hierarchical (Nested) State Machines

<table>
<thead><tr><th>Code</th><th>Statechart</th></tr></thead>
<tbody>
<tr>
<td>

```js
import { createMachine, createActor } from 'xstate';

const pedestrianStates = {
  initial: 'walk',
  states: {
    walk: {
      on: {
        PED_TIMER: 'wait'
      }
    },
    wait: {
      on: {
        PED_TIMER: 'stop'
      }
    },
    stop: {}
  }
};

const lightMachine = createMachine({
  id: 'light',
  initial: 'green',
  states: {
    green: {
      on: {
        TIMER: 'yellow'
      }
    },
    yellow: {
      on: {
        TIMER: 'red'
      }
    },
    red: {
      on: {
        TIMER: 'green'
      },
      ...pedestrianStates
    }
  }
});

const actor = createActor(lightMachine);

actor.subscribe((state) => {
  console.log(state.value);
});

actor.start();
// logs 'green'

actor.send({ type: 'TIMER' });
// logs 'yellow'

actor.send({ type: 'TIMER' });
// logs { red: 'walk' }

actor.send({ type: 'PED_TIMER' });
// logs { red: 'wait' }
```

</td>
<td>
<a href="https://stately.ai/registry/editor/fa443471-b416-4014-8e6f-12417863e4d4?mode=design&machineId=30dffcdd-16c2-49e2-bfc6-a674057cb271" title="Hierarchical states">
  <img src="https://github.com/statelyai/xstate/assets/1093738/32b0692b-1c29-4469-b5e3-03146e3ef249" alt="Hierarchical states" width="400" />
  <br />
  Open in Stately Studio
</a>
<br />
</td>
</tr>
</tbody>
</table>

## Parallel State Machines

<table>
<thead><tr><th>Code</th><th>Statechart</th></tr></thead>
<tbody>
<tr>
<td>

```
/* Detailed source-code truncated for AI context efficiency. */
```

</td>
<td>
<a href="https://stately.ai/registry/editor/fa443471-b416-4014-8e6f-12417863e4d4?mode=design&machineId=980f50d8-e1ff-4441-8c8b-afe41c1610f2" title="Parallel states">
  <img src="https://github.com/statelyai/xstate/assets/1093738/3b1989c0-f4a9-4653-baf2-4df3a40e91a6" alt="Parallel states" width="400" />
  <br />
  Open in Stately Studio
</a>
</td>
</tr>
</tbody>
</table>

## History States

<table>
<thead><tr><th>Code</th><th>Statechart</th></tr></thead>
<tbody>
<tr>
<td>

```js
import { createMachine, createActor } from 'xstate';

const paymentMachine = createMachine({
  id: 'payment',
  initial: 'method',
  states: {
    method: {
      initial: 'cash',
      states: {
        cash: {
          on: {
            SWITCH_CHECK: 'check'
          }
        },
        check: {
          on: {
            SWITCH_CASH: 'cash'
          }
        },
        hist: { type: 'history' }
      },
      on: { NEXT: 'review' }
    },
    review: {
      on: { PREVIOUS: 'method.hist' }
    }
  }
});

const actor = createActor(paymentMachine);

actor.subscribe((state) => {
  console.log(state.value);
});

actor.start();
// logs {
//   value: { method: 'cash' },
// }

actor.send({ type: 'SWITCH_CHECK' });
// logs {
//   value: { method: 'check' },
// }

actor.send({ type: 'NEXT' });
// logs {
//   value: 'review',
// }

actor.send({ type: 'PREVIOUS' });
// logs {
//   value: { method: 'check' },
// }
```

</td>
<td>
<a href="https://stately.ai/registry/editor/fa443471-b416-4014-8e6f-12417863e4d4?mode=design&machineId=d1a9bb95-db97-4af3-b38b-71b005c643d3" title="History states">
  <img src="https://github.com/statelyai/xstate/assets/1093738/1be5c495-d560-4660-94f2-5341efbf7128" alt="History state" width="400" />
  <br />
  Open in Stately Studio
</a>
</td>
</tr>
</tbody>
</table>

## SemVer Policy

We understand the importance of the public contract and do not intend to release any breaking changes to the **runtime** API in a minor or patch release. We consider this with any changes we make to the XState libraries and aim to minimize their effects on existing users.

### Breaking changes

XState executes much of the user logic itself. Therefore, almost any change to its behavior might be considered a breaking change. We recognize this as a potential problem but believe that treating every change as a breaking change is not practical. We do our best to implement new features thoughtfully to enable our users to implement their logic in a better, safer way.

Any change _could_ affect how existing XState machines behave if those machines are using particular configurations. We do not introduce behavior changes on a whim and aim to avoid making changes that affect most existing machines. But we reserve the right to make _some_ behavior changes in minor releases. Our best judgment of the situation will always dictate such changes. Please always read our release notes before deciding to upgrade.

### TypeScript changes

We also reserve a similar right to adjust declared TypeScript definitions or drop support for older versions of TypeScript in a minor release. The TypeScript language itself evolves quickly and often introduces breaking changes in its minor releases. Our team is also continuously learning how to leverage TypeScript more effectively - and the types improve as a result.

For these reasons, it is impractical for our team to be bound by decisions taken when an older version of TypeScript was its latest version or when we didn’t know how to declare our types in a better way. We won’t introduce declaration changes often - but we are more likely to do so than with runtime changes.

### Packages

Most of the packages in the XState family declare a peer dependency on XState itself. We’ll be cautious about maintaining compatibility with already-released packages when releasing a new version of XState, **but** each release of packages depending on XState will always adjust the declared peer dependency range to include the latest version of XState. For example, you should always be able to update `xstate` without `@xstate/react`. But when you update `@xstate/react`, we highly recommend updating `xstate` too.

---

### Overview (`.changeset/README.md`)

# Changesets

Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)

We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)

---

### Overview (`examples/readme.md`)

# Contributing an example

These steps assume You've forked the repo and created a branch for your PR. For more info, see the section _Making changes_ in our [CONTRIBUTING.md](https://github.com/statelyai/xstate/blob/main/CONTRIBUTING.md#making-changes).

1. In the CLI, navigate to the `/examples` folder. Start a [new Vite project](https://vitejs.dev/guide/#scaffolding-your-first-vite-project) using the appropriate template (e.g. `react-ts`) and adding the name of the framework at the end of your example's name:

```bash
pnpm create vite@latest my-example-react --template react-ts
cd my-example-react
```

2. Install `xstate` and the library-specific beta (e.g. `@xstate/react`):

```bash
pnpm install xstate @xstate/react
```

3. Add your XState-powered demo code ✨

4. Preview it:

```bash
pnpm run dev
```

5. Submit a PR!

---

### Overview (`examples/7guis-1-counter-vue/README.md`)

# Counter

This is a counter built with:

- XState v5
- Vue
- TypeScript
- Vite

It's the 1st task of the [7 GUIs](https://eugenkiss.github.io/7guis).

## Demo Video

[7GUIs -- cute -- 1.webm](https://github.com/tsxoxo/xstate/assets/59713582/64b224b3-3a72-497f-9933-6a0c1dc6c01d)

## Live

[Open in CodeSandbox](https://codesandbox.io/p/sandbox/github/statelyai/xstate/tree/main/examples/7guis-1-counter-vue)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/examples/7guis-1-counter-vue)

---

### Overview (`examples/7guis-2-temperature-vue/README.md`)

# Temperature Converter

This is a temperature converter built with:

- XState v5
- Vue
- TypeScript
- Vite

It's the 2nd task of the [7 GUIs](https://eugenkiss.github.io/7guis).

## Demo Video

[7GUIs -- cute -- 2.webm](https://github.com/tsxoxo/xstate/assets/59713582/313e6b07-97d7-4c6c-99cb-ee376fa03267)

## Live

[Open in CodeSandbox](https://codesandbox.io/p/sandbox/github/statelyai/xstate/tree/main/examples/7guis-2-temperature-vue)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/examples/7guis-2-temperature-vue)

---

### Overview (`examples/7guis-counter-react/readme.md`)

# 7GUIs Counter

This is an implementation of [the 7GUIs counter](https://eugenkiss.github.io/7guis/tasks#counter) built with:

- XState v5
- React
- TypeScript
- Vite

## [Open in CodeSandbox](https://codesandbox.io/p/sandbox/github/statelyai/xstate/tree/main/examples/7guis-counter-react)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/examples/7guis-counter-react)

---

### Overview (`examples/7guis-flight-booker-react/README.md`)

# XState v5 + React - 7GUIs Flight Booker

The 7GUIs Fligt Booker App built with:

- React 18
- XState 5
- Typescript
- Vite

Visit the [7GUIs project](https://eugenkiss.github.io/7guis/tasks#flight/ 'Flight Booker') for more info.

## Screenshots



[](https://stackblitz.com/github/statelyai/xstate/tree/main/examples/7guis-flight-booker-react)

---

### Overview (`examples/7guis-temperature-react/readme.md`)

# 7GUIs Temperature

This is an implementation of [the 7GUIs temperature converter](https://eugenkiss.github.io/7guis/tasks#temp) built with:

- XState v5
- React
- TypeScript
- Vite

## [Open in CodeSandbox](https://codesandbox.io/p/sandbox/github/statelyai/xstate/tree/main/examples/7guis-temperature-react)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/examples/7guis-temperature-react)

---

### Overview (`examples/counter/readme.md`)

# Simple counter

This is an implementation of a simple counter, built with:

- XState v5
- TypeScript
- Vite

## [Open in CodeSandbox](https://codesandbox.io/p/sandbox/github/statelyai/xstate/tree/main/examples/counter)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/examples/counter)

---

### Overview (`examples/express-workflow/README.md`)

# Express simple workflow engine

This is a simple workflow engine built with:

- XState v5
- TypeScript
- Express

[](https://stackblitz.com/github/statelyai/xstate/tree/main/examples/express-workflow?file=index.ts)

## Usage

```bash
pnpm install
pnpm start
```

## Endpoints

### POST `/workflows`

Creates a new workflow instance.

```bash
curl -X POST http://localhost:4242/workflows
```

Example response:

```json
{
  "workflowId": "7ky252"
}
```

### POST `/workflows/:id`

Sends an event to a workflow instance.

```bash
# Replace :id with the workflow ID; e.g. http://localhost:4242/workflows/7ky252
# the body should be JSON
curl -X POST http://localhost:4242/workflows/:id -d '{"type": "TIMER"}' -H "Content-Type: application/json"
```

### GET `/workflows/:id`

Gets the current state of a workflow instance.

```bash
curl -X GET http://localhost:4242/workflows/:id
```

---

### Overview (`examples/fetch/README.md`)

# Fetch

This is a simple fetch example built with:

- XState v5
- Parcel

## [Open in CodeSandbox](https://codesandbox.io/p/sandbox/github/statelyai/xstate/tree/main/examples/fetch)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/examples/fetch)

---

### Overview (`examples/friends-list-react/readme.md`)

# React list

This is a React list built with:

- XState v5
- React
- TypeScript
- Vite

## [Open in CodeSandbox](https://codesandbox.io/p/sandbox/github/statelyai/xstate/tree/main/examples/friends-list-react)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/examples/friends-list-react)

---

### Overview (`examples/local-store-counter-react/README.md`)

# Counter example (`@xstate/store`)

This is a simple counter example, built with:

- [XState Store](https://github.com/statelyai/xstate/tree/main/packages/xstate-store)
- React
- TypeScript
- Vite

## [Open in CodeSandbox](https://codesandbox.io/p/sandbox/github/statelyai/xstate/tree/main/examples/store-counter-react)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/examples/store-counter-react)

---

### Overview (`examples/mongodb-credit-check-api/README.md`)

# Express Credit Check Workflow

This is a simple workflow engine built with:

- XState v5
- TypeScript
- Express

This is a modified version of the express-workflow project that shows how to implement state hydration in the `actorService.ts` file.
It also uses a more complex machine with guards, actions, and parallel states configured.

**NOTE**: This project is _not_ production-ready and is intended for educational purposes.

## Usage

[MongoDB](https://www.mongodb.com/docs/manual/administration/install-community/) should be configured with a database named `creditCheck`.

We recommend installing the [MongoDB Compass app](https://www.mongodb.com/products/tools/compass) to view the contents of your database while you run this project.

Add the connection string to the DB client in the `actorService.ts` file by updating this line:

```typescript
const uri = '<your mongo uri here>/creditCheck';
```

```bash
pnpm install
pnpm start
```

## Endpoints

### POST `/workflows`

Creates a new workflow instance.

```bash
curl -X POST http://localhost:4242/workflows
```

Example response:
`201 - Created`

```json
{
  {"message":"New workflow created successfully","workflowId":"uzkjyy"}
}
```

### POST `/workflows/:id`

`200 - OK`

Sends an event to a workflow instance.

```bash
# Replace :id with the workflow ID; e.g. http://localhost:4242/workflows/7ky252
# the body should be JSON
curl -X POST http://localhost:4242/workflows/:id -d '{"type": "Submit", "SSN": "123456789", "lastName": "Bauman", "firstName": "Gavin"}' -H "Content-Type: application/json"
```

### GET `/workflows/:id`

Gets the current state of a workflow instance.

```bash
curl -X GET http://localhost:4242/workflows/:id
```

---

### Overview (`examples/mongodb-persisted-state/README.md`)

# Persistent State Storage and Hydration with MongoDB

## What it is

This example demonstrates how to hook the MongoDB client into your running state machine for persistence.
Specifically, it connects to a running instance of a MongoDB service, saves a snapshot of the Actor's state in the DB, and retrieves it whenever the Actor receives an event.
The Actor is bound to a single record in the database, and will only ever update that record.
If one doesn't already exist, like in the case of a first run, we create the state file in the database.
This is particularly useful for working through long-running stateful flows, or flows where the underlying compute is not promised to be consistent.

> [!IMPORTANT]
>
> This example is intended to be used as a starting point. It is not production-ready. For example, when connecting to the MongoDB client, all strings should be URI-encoded when authenticating to MongoDB. Check out [MongoDB's Node driver docs](https://www.mongodb.com/docs/drivers/node/current/fundamentals/authentication/mechanisms/) for more details.

## Prerequisites

To get this sample working, you'll need the following:

- A live [MongoDB database deployment](https://www.mongodb.com/docs/atlas/create-connect-deployments/). There is no need to explicitly create the collections in the deployment. If they don't exist, the MongoClient will create them on your behalf.
- A connection string to the running database. This is obtained by selecting the Connect option if you're using MongoDB's Atlas service

## Running the sample

1. Open a terminal in this folder and run `yarn install`. This will install the beta version of XState v5, the proper Node.JS driver for MongoDB, and `ts-node` for running this sample in your terminal.

2. Replace the following line with your own connection string, or load it in as an environment variable:

```ts
const uri = '<your mongodb connection string>';
```

3. Run the following command in the terminal to start the project:

```
yarn ts-node --esm ./main.ts
```

And that's it! Feel free to send the machine events, killing the program between events, and restarting it to ensure it hydrates properly. Be sure to check your Mongo DB collection for changes!

---

### Overview (`examples/snake-react/README.md`)

# React Snake

This is an implementation of the game Snake built with:

- XState v5
- React
- TypeScript
- Vite

## [Open in CodeSandbox](https://codesandbox.io/p/sandbox/github/statelyai/xstate/tree/main/examples/snake-react)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/examples/snake-react)

Adapted from https://github.com/josmithua/xsnake

---

### Overview (`examples/stopwatch/readme.md`)

# Stopwatch

This is a simple stopwatch, built with:

- XState v5
- TypeScript
- Vite

## [Open in CodeSandbox](https://codesandbox.io/p/sandbox/github/statelyai/xstate/tree/main/examples/stopwatch)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/examples/stopwatch)

---

### Overview (`examples/store-counter-react/README.md`)

# Counter example (`@xstate/store`)

This is a simple counter example, built with:

- [XState Store](https://github.com/statelyai/xstate/tree/main/packages/xstate-store)
- React
- TypeScript
- Vite

## [Open in CodeSandbox](https://codesandbox.io/p/sandbox/github/statelyai/xstate/tree/main/examples/store-counter-react)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/examples/store-counter-react)

---

### Overview (`examples/store-tic-tac-toe/README.md`)

# Tic-tac-toe example (`@xstate/store`)

This is an implementation of tic-tac-toe built with:

- [XState Store](https://github.com/statelyai/xstate/tree/main/packages/xstate-store)
- React
- TypeScript
- Vite

## [Open in CodeSandbox](https://codesandbox.io/p/sandbox/github/statelyai/xstate/tree/main/examples/store-tic-tac-toe)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/examples/store-tic-tac-toe)

---

### Overview (`examples/tic-tac-toe-react/readme.md`)

# React tic-tac-toe

This is an implementation of tic-tac-toe built with:

- XState v5
- React
- TypeScript
- Vite

## [Open in CodeSandbox](https://codesandbox.io/p/sandbox/github/statelyai/xstate/tree/main/examples/tic-tac-toe-react)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/examples/tic-tac-toe-react)

---

### Overview (`examples/tiles/readme.md`)

# Tiles game

This is a simple tiles game, built with:

- XState v5
- React
- TypeScript
- Vite

## [Open in CodeSandbox](https://codesandbox.io/p/sandbox/github/statelyai/xstate/tree/main/examples/tiles)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/examples/tiles)

---

### Overview (`examples/timer/readme.md`)

# Timer

This is a timer, built with:

- XState v5
- React
- TypeScript
- Vite

## [Open in CodeSandbox](https://codesandbox.io/p/sandbox/github/statelyai/xstate/tree/main/examples/timer)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/examples/timer)

---

### Overview (`examples/todomvc-react/readme.md`)

# TodoMVC React

This is an implementation of [TodoMVC](https://todomvc.com/) built with:

- XState v5
- React
- TypeScript
- Vite

## How to run

You may run the example locally with:

```shell
    cd examples/todomvc-react
    pnpm install
    pnpm run dev
```

**OR**

[Open in CodeSandbox](https://codesandbox.io/p/sandbox/github/statelyai/xstate/tree/main/examples/todomvc-react)

**OR**

[](https://stackblitz.com/github/statelyai/xstate/tree/main/examples/todomvc-react)

---

### Overview (`examples/toggle/readme.md`)

# Toggle

This is a simple toggle, built with:

- XState v5
- TypeScript
- Vite

## [Open in CodeSandbox](https://codesandbox.io/p/sandbox/github/statelyai/xstate/tree/main/examples/toggle)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/examples/toggle)

---

### Overview (`examples/trivia-game-example/README.md`)

# Trivia Game Rick & Morty

This app is a trivia game based on the Rick & Morty characters. The user has to select the right character based on a single image and four different options. The rules are the following:

- The user has 3 lifes and zero points at the start
- If the user guesses the character correctly then 10 points will be awarded
- If the user makes an incorrect guess then one life will be taken
- The user has one clue for each question
- The game is won by achieving 100 points
- The game is lost if all lifes are lost
- You can reset and play again after losing or winning

## Machine Context

In order for the machine to work, we need to define first the context for it. The context has all the variables needed that the machine can access and modify.
<img width="504" alt="image" src="https://github.com/natar10/trivia-rm/assets/12553364/c1ab0219-d76a-4b9b-b087-4e36094991be">

## States and transitions

A machine is composed of states. Each state defines where the app can be, and also the logic that can be applied. If we need to move to another state, we call a transition. The transitions define the destination and origin state to where the app can go to.
For example:
<img width="734" alt="image" src="https://github.com/natar10/trivia-rm/assets/12553364/29d90483-0366-4a3c-b7b7-c071c63e4579">

Here we have our initial state: `questionStart`. To move to another state, we use the transition `user.selectAnswer`. If the answer is correct we'll go to the `correctAnswer` state, otherwise we'll end up in the `incorrectAnswer` state.

You can see the complete machine for this project [here](https://stately.ai/registry/editor/f64904b1-65f9-4946-aace-ddfc9fd05c29?machineId=aec325d6-2d51-4334-afc4-f2c02a67aa05)

### Installation

Install all required packages with:

```bash
pnpm install
```

### Development

Start the development server on http://localhost:5173

```bash
yarn dev
```

---

### Overview (`examples/workflow-media-scanner/README.md`)

# Workflow Example: Scanning and splitting Media

This is a small example of a back-end workflow that uses a state machine to execute long running tasks. This project crawls a directory full of movies and separates out videos over 1080p for potential processing down the line.

> **NOTE:This project is not intended for production use.**

## Prerequisites

This project requires `ffprobe`, a binary that ships alongside `ffmpeg`, which is the golden standard for media file manipulation.

- [Install ffmpeg here](https://ffmpeg.org/download.html)
- Clone this repo and run `yarn` (or use your package manager of choice) in a terminal at the project's root.
- Update the `basePath` and `destinationPath` in the `mediaScannerMachine.ts` file with your own paths.
- Run the project with `yarn start` in the terminal

## XState concepts involved

This project convers how to implement the following with XState:

- Initializing a XState machine as an actor

  ```ts
  // index.ts

  // ...

  const mediaScannerActor = createActor(mediaScannerMachine);
  ```

- Injecting context information into the actor on initialization

  ```ts
  // index.ts

  // ...

  const mediaScannerActor = createActor(mediaScannerMachine, {
    input: {
      basePath: 'YOUR BASE PATH HERE',
      destinationPath: 'YOUR DESTINATION PATH HERE'
    }
  });
  ```

- Sending events to the XState actor

  ```ts
  // index.ts

  // ...

  mediaScannerActor.send({ type: 'START_SCAN' });
  ```

- Subscribing to a running actor for state change and context information

  ```ts
  // index.ts

  // ...

  mediaScannerActor.subscribe((state) => {
    console.log({
      state: state.value,
      error: state.error,
      context: state.context
    });
  });
  ```

- Invoking services and capturing results

  > mediaScannerMachine.ts

  ```ts
  invoke: {
    id: 'checkFilePermissions',
    input: ({ context: { directoriesToCheck } }) => ({
      directoriesToCheck
    }),
    src: fromPromise(async ({ input: { directoriesToCheck } }) =>
      await checkFilePermissions(directoriesToCheck)
    ),
    onDone: [
      {
        target: 'EvaluatingFiles',
        actions: assign(({ event }) => {
          return {
            dirsToEvaluate: event.output['dirsToEvaluate'],
            dirsToReport: event.output['dirsToReport']
          };
        })
      }
    ],
    onError: [
      {
        target: 'ReportingErrors',
        actions: assign(({ event }) => {
          return {
            dirsToReport: event.error['dirsToReport']
          };
        })
      }
    ]
  }
  ```

- Batching results and assigning multiple properties to the actor's context

  > fileHandlers.ts

  ```ts
  ...
   return { dirsToEvaluate, dirsToReport };
  ```

  > mediaScannerMachine.ts

  ```ts
  actions: assign(({ event }) => {
    return {
      dirsToEvaluate: event.output['dirsToEvaluate'],
      dirsToReport: event.output['dirsToReport']
    };
  });
  ```

---

### Overview (`packages/core/README.md`)

<p align="center">
  <br />

  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/statelyai/public-assets/main/logos/xstate-logo-white-nobg.svg">
    <img alt="XState logotype" src="https://raw.githubusercontent.com/statelyai/public-assets/main/logos/xstate-logo-black-nobg.svg" width="200">
  </picture>
  <br />
    <strong>Actor-based state management & orchestration for complex app logic.</strong> <a href="https://stately.ai/docs">→ Documentation</a>
  <br />
  <br />
</p>

XState is a state management and orchestration solution for JavaScript and TypeScript apps. It has _zero_ dependencies, and is useful for frontend and backend application logic.

It uses event-driven programming, state machines, statecharts, and the actor model to handle complex logic in predictable, robust, and visual ways. XState provides a powerful and flexible way to manage application and workflow state by allowing developers to model logic as actors and state machines.

### ✨ Create state machines visually in Stately Studio → [state.new](https://state.new)

---

📖 [Read the documentation](https://stately.ai/docs)

➡️ [Create state machines with the Stately Editor](https://stately.ai/editor)

🖥 [Download our VS Code extension](https://marketplace.visualstudio.com/items?itemName=statelyai.stately-vscode)

📑 Inspired by the [SCXML specification](https://www.w3.org/TR/scxml/)

💬 Chat on the [Stately Discord Community](https://discord.gg/xstate)

✍️ Browse through the many [XState examples](https://github.com/statelyai/xstate/tree/main/examples)

## Templates

Get started by forking one of these templates on CodeSandbox:

<table>
<thead>
<tr><th>Template</th><th></th></tr>
</thead>
<tbody>

<tr>
<td>

[🤖 XState Template (CodeSandbox)](https://codesandbox.io/p/devbox/github/statelyai/xstate/tree/main/templates/vanilla-ts)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/templates/vanilla-ts?file=%2Fsrc%2FfeedbackMachine.ts)

</td>
<td>

- XState v5
- TypeScript
- _No framework_

</td>
</tr>

<tr>
<td>

[⚛️ XState + React Template (CodeSandbox)](https://codesandbox.io/p/devbox/github/statelyai/xstate/tree/main/templates/react-ts)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/templates/react-ts?file=%2Fsrc%2FfeedbackMachine.ts)

</td>
<td>

- [React](https://react.dev/)
- XState v5
- TypeScript

</td>
</tr>

<tr>
<td>

[💚 XState + Vue Template (CodeSandbox)](https://codesandbox.io/p/devbox/github/statelyai/xstate/tree/main/templates/vue-ts)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/templates/vue-ts?file=%2Fsrc%2FfeedbackMachine.ts)

</td>
<td>

- [Vue](https://vuejs.org/)
- XState v5
- TypeScript

</td>
</tr>

<tr>
<td>

[🧡 XState + Svelte Template (CodeSandbox)](https://codesandbox.io/p/devbox/github/statelyai/xstate/tree/main/templates/svelte-ts)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/templates/svelte-ts?file=%2Fsrc%2FfeedbackMachine.ts)

</td>
<td>

- [Svelte](https://svelte.dev/)
- XState v5
- TypeScript

</td>
</tr>

</tbody>
</table>

## Super quick start

```bash
npm install xstate
```

```ts
import { createMachine, createActor, assign } from 'xstate';

// State machine
const toggleMachine = createMachine({
  id: 'toggle',
  initial: 'inactive',
  context: {
    count: 0
  },
  states: {
    inactive: {
      on: {
        TOGGLE: { target: 'active' }
      }
    },
    active: {
      entry: assign({ count: ({ context }) => context.count + 1 }),
      on: {
        TOGGLE: { target: 'inactive' }
      }
    }
  }
});

// Actor (instance of the machine logic, like a store)
const toggleActor = createActor(toggleMachine);
toggleActor.subscribe((state) => console.log(state.value, state.context));
toggleActor.start();
// => logs 'inactive', { count: 0 }

toggleActor.send({ type: 'TOGGLE' });
// => logs 'active', { count: 1 }

toggleActor.send({ type: 'TOGGLE' });
// => logs 'inactive', { count: 1 }
```

## [Stately Studio](https://stately.ai)

- Visually create, edit, and collaborate on state machines
- Export to many formats, including XState v5
- Test path & documentation autogeneration
- Deploy to Stately Sky
- Generate & modify machines with Stately AI

<a href="https://stately.ai/registry/new?ref=github" title="Stately Studio">
  <img src="https://github.com/statelyai/xstate/assets/1093738/74ed9cbc-b824-4ed7-a16d-f104947af8a7" alt="XState Viz" width="800" />
</a>

**[state.new](https://stately.ai/registry/new?ref=github)**

## Why?

Statecharts are a formalism for modeling stateful, reactive systems. This is useful for declaratively describing the _behavior_ of your application, from the individual components to the overall application logic.

Read [📽 the slides](http://slides.com/davidkhourshid/finite-state-machines) ([🎥 video](https://www.youtube.com/watch?v=VU1NKX6Qkxc)) or check out these resources for learning about the importance of finite state machines and statecharts in user interfaces:

- [Statecharts - A Visual Formalism for Complex Systems](https://www.sciencedirect.com/science/article/pii/0167642387900359/pdf) by David Harel
- [The World of Statecharts](https://statecharts.github.io/) by Erik Mogensen

## Packages

| Package                                                                                       | Description                                                                  |
| --------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| 🤖 `xstate`                                                                                   | Core finite state machine and statecharts library + interpreter              |
| [⚛️ `@xstate/react`](https://github.com/statelyai/xstate/tree/main/packages/xstate-react)     | React hooks and utilities for using XState in React applications             |
| [💚 `@xstate/vue`](https://github.com/statelyai/xstate/tree/main/packages/xstate-vue)         | Vue composition functions and utilities for using XState in Vue applications |
| [🎷 `@xstate/svelte`](https://github.com/statelyai/xstate/tree/main/packages/xstate-svelte)   | Svelte utilities for using XState in Svelte applications                     |
| [🥏 `@xstate/solid`](https://github.com/statelyai/xstate/tree/main/packages/xstate-solid)     | Solid hooks and utilities for using XState in Solid applications             |
| [🔍 `@xstate/inspect`](https://github.com/statelyai/xstate/tree/main/packages/xstate-inspect) | Inspection utilities for XState                                              |

## Finite State Machines

<table>
<thead><tr><th>Code</th><th>Statechart</th></tr></thead>
<tbody>
<tr>
<td>

```js
import { createMachine, createActor } from 'xstate';

const lightMachine = createMachine({
  id: 'light',
  initial: 'green',
  states: {
    green: {
      on: {
        TIMER: 'yellow'
      }
    },
    yellow: {
      on: {
        TIMER: 'red'
      }
    },
    red: {
      on: {
        TIMER: 'green'
      }
    }
  }
});

const actor = createActor(lightMachine);

actor.subscribe((state) => {
  console.log(state.value);
});

actor.start();
// logs 'green'

actor.send({ type: 'TIMER' });
// logs 'yellow'
```

<table>
<thead><tr><th>Code</th><th>Statechart</th></tr></thead>
<tbody>
<tr>
<td>

</td>
<td>

</td>
</tr>
</tbody>
</table>

</td>
<td>

<a href="https://stately.ai/registry/editor/fa443471-b416-4014-8e6f-12417863e4d4?mode=design&machineId=27e86036-f2f7-40f1-9d1e-66ce6e1accc0" title="Finite states">
  <img src="https://github.com/statelyai/xstate/assets/1093738/36d4b6b5-e3d0-4c19-9f41-2e3425ceac88" alt="Finite states" width="400" />
  <br />
  Open in Stately Studio
</a>
<br />

</td>
</tbody>
</table>

## Hierarchical (Nested) State Machines

<table>
<thead><tr><th>Code</th><th>Statechart</th></tr></thead>
<tbody>
<tr>
<td>

```js
import { createMachine, createActor } from 'xstate';

const pedestrianStates = {
  initial: 'walk',
  states: {
    walk: {
      on: {
        PED_TIMER: 'wait'
      }
    },
    wait: {
      on: {
        PED_TIMER: 'stop'
      }
    },
    stop: {}
  }
};

const lightMachine = createMachine({
  id: 'light',
  initial: 'green',
  states: {
    green: {
      on: {
        TIMER: 'yellow'
      }
    },
    yellow: {
      on: {
        TIMER: 'red'
      }
    },
    red: {
      on: {
        TIMER: 'green'
      },
      ...pedestrianStates
    }
  }
});

const actor = createActor(lightMachine);

actor.subscribe((state) => {
  console.log(state.value);
});

actor.start();
// logs 'green'

actor.send({ type: 'TIMER' });
// logs 'yellow'

actor.send({ type: 'TIMER' });
// logs { red: 'walk' }

actor.send({ type: 'PED_TIMER' });
// logs { red: 'wait' }
```

</td>
<td>
<a href="https://stately.ai/registry/editor/fa443471-b416-4014-8e6f-12417863e4d4?mode=design&machineId=30dffcdd-16c2-49e2-bfc6-a674057cb271" title="Hierarchical states">
  <img src="https://github.com/statelyai/xstate/assets/1093738/32b0692b-1c29-4469-b5e3-03146e3ef249" alt="Hierarchical states" width="400" />
  <br />
  Open in Stately Studio
</a>
<br />
</td>
</tr>
</tbody>
</table>

## Parallel State Machines

<table>
<thead><tr><th>Code</th><th>Statechart</th></tr></thead>
<tbody>
<tr>
<td>

```
/* Detailed source-code truncated for AI context efficiency. */
```

</td>
<td>
<a href="https://stately.ai/registry/editor/fa443471-b416-4014-8e6f-12417863e4d4?mode=design&machineId=980f50d8-e1ff-4441-8c8b-afe41c1610f2" title="Parallel states">
  <img src="https://github.com/statelyai/xstate/assets/1093738/3b1989c0-f4a9-4653-baf2-4df3a40e91a6" alt="Parallel states" width="400" />
  <br />
  Open in Stately Studio
</a>
</td>
</tr>
</tbody>
</table>

## History States

<table>
<thead><tr><th>Code</th><th>Statechart</th></tr></thead>
<tbody>
<tr>
<td>

```js
import { createMachine, createActor } from 'xstate';

const paymentMachine = createMachine({
  id: 'payment',
  initial: 'method',
  states: {
    method: {
      initial: 'cash',
      states: {
        cash: {
          on: {
            SWITCH_CHECK: 'check'
          }
        },
        check: {
          on: {
            SWITCH_CASH: 'cash'
          }
        },
        hist: { type: 'history' }
      },
      on: { NEXT: 'review' }
    },
    review: {
      on: { PREVIOUS: 'method.hist' }
    }
  }
});

const actor = createActor(paymentMachine);

actor.subscribe((state) => {
  console.log(state.value);
});

actor.start();
// logs {
//   value: { method: 'cash' },
// }

actor.send({ type: 'SWITCH_CHECK' });
// logs {
//   value: { method: 'check' },
// }

actor.send({ type: 'NEXT' });
// logs {
//   value: 'review',
// }

actor.send({ type: 'PREVIOUS' });
// logs {
//   value: { method: 'check' },
// }
```

</td>
<td>
<a href="https://stately.ai/registry/editor/fa443471-b416-4014-8e6f-12417863e4d4?mode=design&machineId=d1a9bb95-db97-4af3-b38b-71b005c643d3" title="History states">
  <img src="https://github.com/statelyai/xstate/assets/1093738/1be5c495-d560-4660-94f2-5341efbf7128" alt="History state" width="400" />
  <br />
  Open in Stately Studio
</a>
</td>
</tr>
</tbody>
</table>

## Sponsors

Special thanks to the sponsors who support this open-source project:

<img src="https://opencollective.com/xstate/tiers/backer/badge.svg?label=sponsors&color=brightgreen" />

<a href="https://transloadit.com/?utm_source=xstate&utm_medium=referral&utm_campaign=sponsorship&utm_content=github">
  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="https://assets.transloadit.com/assets/images/sponsorships/logo-dark.svg">
    <source media="(prefers-color-scheme: light)" srcset="https://assets.transloadit.com/assets/images/sponsorships/logo-default.svg">
    <img src="https://assets.transloadit.com/assets/images/sponsorships/logo-default.svg" alt="Transloadit Logo">
  </picture>
</a>

## SemVer Policy

We understand the importance of the public contract and do not intend to release any breaking changes to the **runtime** API in a minor or patch release. We consider this with any changes we make to the XState libraries and aim to minimize their effects on existing users.

### Breaking changes

XState executes much of the user logic itself. Therefore, almost any change to its behavior might be considered a breaking change. We recognize this as a potential problem but believe that treating every change as a breaking change is not practical. We do our best to implement new features thoughtfully to enable our users to implement their logic in a better, safer way.

Any change _could_ affect how existing XState machines behave if those machines are using particular configurations. We do not introduce behavior changes on a whim and aim to avoid making changes that affect most existing machines. But we reserve the right to make _some_ behavior changes in minor releases. Our best judgment of the situation will always dictate such changes. Please always read our release notes before deciding to upgrade.

### TypeScript changes

We also reserve a similar right to adjust declared TypeScript definitions or drop support for older versions of TypeScript in a minor release. The TypeScript language itself evolves quickly and often introduces breaking changes in its minor releases. Our team is also continuously learning how to leverage TypeScript more effectively - and the types improve as a result.

For these reasons, it is impractical for our team to be bound by decisions taken when an older version of TypeScript was its latest version or when we didn’t know how to declare our types in a better way. We won’t introduce declaration changes often - but we are more likely to do so than with runtime changes.

### Packages

Most of the packages in the XState family declare a peer dependency on XState itself. We’ll be cautious about maintaining compatibility with already-released packages when releasing a new version of XState, **but** each release of packages depending on XState will always adjust the declared peer dependency range to include the latest version of XState. For example, you should always be able to update `xstate` without `@xstate/react`. But when you update `@xstate/react`, we highly recommend updating `xstate` too.

---

### Overview (`packages/xstate-immer/README.md`)

# @xstate/immer

<p align="center">
  <a href="https://xstate.js.org">
  <br />
  <img src="https://user-images.githubusercontent.com/1093738/79572515-1509e180-808b-11ea-92aa-10958521aa68.png" alt="XState Immer" width="200"/>
  <br />
    <sub><strong>XState with Immer</strong></sub>
  <br />
  <br />
  </a>
</p>

This package contains utilities for using [Immer](https://immerjs.github.io/immer/docs/introduction) with [XState](https://github.com/statelyai/xstate).

- [Read the full documentation in the XState docs](https://xstate.js.org/docs/packages/xstate-immer/).
- [Read our contribution guidelines](https://github.com/statelyai/xstate/blob/main/CONTRIBUTING.md).

## Quick start

Included in `@xstate/immer`:

- `assign()` - an Immer action that allows you to immutably assign to machine `context` in a convenient way
- `createUpdater()` - a useful function that allows you to cohesively define a context update event event creator and assign action, all together. ([See an example](#createupdatereventtype-recipe) below)

1. Install `immer`, `xstate`, `@xstate/immer`:

```bash
npm install immer xstate @xstate/immer
```

**Note:** You don't need to `import` anything from `immer`; it is a peer-dependency of `@xstate/immer`, so it must be installed.

2. Import the Immer utilities:

```js
import { createMachine, interpret } from 'xstate';
import { assign, createUpdater } from '@xstate/immer';

const levelUpdater = createUpdater('UPDATE_LEVEL', (ctx, { input }) => {
  ctx.level = input;
});

const toggleMachine = createMachine({
  id: 'toggle',
  context: {
    count: 0,
    level: 0
  },
  initial: 'inactive',
  states: {
    inactive: {
      on: {
        TOGGLE: {
          target: 'active',
          // Immutably update context the same "mutable"
          // way as you would do with Immer!
          actions: assign((ctx) => ctx.count++)
        }
      }
    },
    active: {
      on: {
        TOGGLE: {
          target: 'inactive'
        },
        // Use the updater for more convenience:
        [levelUpdater.type]: {
          actions: levelUpdater.action
        }
      }
    }
  }
});

const toggleService = interpret(toggleMachine)
  .onTransition((state) => {
    console.log(state.context);
  })
  .start();

toggleService.send({ type: 'TOGGLE' });
// { count: 1, level: 0 }

toggleService.send(levelUpdater.update(9));
// { count: 1, level: 9 }

toggleService.send({ type: 'TOGGLE' });
// { count: 2, level: 9 }

toggleService.send(levelUpdater.update(-100));
// Notice how the level is not updated in 'inactive' state:
// { count: 2, level: 9 }
```

---

### Overview (`packages/xstate-inspect/README.md`)

# @xstate/inspect

This package contains inspection tools for XState.

- [Read the full documentation in the XState docs](https://xstate.js.org/docs/packages/xstate-inspect/).
- [Read our contribution guidelines](https://github.com/statelyai/xstate/blob/main/CONTRIBUTING.md).

## Templates

- [XState (Vanilla)](https://codesandbox.io/s/xstate-ts-viz-template-qzdvv)
- [XState + TypeScript](https://codesandbox.io/s/xstate-ts-viz-template-qzdvv)
- [XState + Vue](https://codesandbox.io/s/xstate-vue-viz-template-r5wd7)
- [XState + React](https://codesandbox.io/s/xstate-react-viz-template-5wq3q)



[Check out the XState + Vue Minute Timer + Viz example on CodeSandbox](https://codesandbox.io/s/xstate-vue-minute-timer-viz-1txmk)

## Installation

1. Install with npm or yarn:

```bash
npm install @xstate/inspect
# or yarn add @xstate/inspect
```

**Via CDN**

```html
<script src="https://unpkg.com/@xstate/inspect/dist/xstate-inspect.umd.min.js"></script>
```

By using the global variable `XStateInspect`

2. Import it at the beginning of your project, before any other code is called:

```js
import { inspect } from '@xstate/inspect';

inspect({
  // options
  // url: 'https://stately.ai/viz?inspect', // (default)
  iframe: false // open in new window
});
```

3. Add `{ devTools: true }` to any interpreted machines you want to visualize:

```js
import { interpret } from 'xstate';
import { inspect } from '@xstate/inspect';
// ...

const service = interpret(someMachine, { devTools: true });
service.start();
```

## Configuration

- `url` _(optional)_ - The endpoint that the Inspector sends events to. Default: https://stately.ai/viz?inspect
- `iframe` _(optional)_ - The iframe that loads the provided URL. If iframe is set to `false`, then a new tab is opened instead.
- `devTools` _(optional)_ - Allows custom implementation for lifecycle hooks.
- `serialize` _(optional)_ - A custom serializer for messages sent to the URL endpoint. Useful for sanitizing sensitive information, such as credentials, from leaving your application.
- `targetWindow` _(optional)_ - Provide a pre-existing window location that will be used instead of opening a new window etc. When using this option, you must still provide the `url` value due to security checks in browser APIs, and the `iframe` option is ignored in such a case.

### Examples

### Add a custom serializer to @xstate/inspector events and transitions messages

When is this useful?

- Remove sensitive items, such as `credentials`
- Add additional custom handling

```typescript
// Remove credentials from being forwarded
inspect({
  serialize: (key: string, value: any) => {
    return key === 'credentials' && typeof value === 'object' ? {} : value;
  }
});

// Add a custom local log
inspect({
  serialize: (key: string, value: any) => {
    if (key === 'ready') {
      console.log('Detected ready key');
    }
    return value;
  }
});
```

### Easily log all machine events and transitions

When is this useful?

- Allows you to quickly see all events and transitions for your machines
- No need to add manual `console.log` statements to your machine definitions

```typescript
// The URL and port of your local project (ex. Vite, Webpack, etc).
const url = 'http://127.0.0.1:5174/';

const inspector = inspect({
  url,
  iframe: undefined,
  targetWindow: window
});

// In the same window, subscribe to messages from @xstate/inspector
createWindowReceiver({}).subscribe(console.log);

// Start your machine, and all events generated are logged to the console
interpret(machine, { devTools: true }).start({});
```

### Send events to a separate, locally hosted tool

When is this useful?

- Forward messages to a custom endpoint, that you can then listen to and add custom handling for messages

```typescript
// In your client application
const url = 'http://127.0.0.1:8443/';
const targetWindow = window.open(url);

const inspector = inspect({
  // The URL must still be provided. This is used by postMessage, as it's
  // not possible to do targetWindow.location for security reasons
  url,
  targetWindow
});

// In the second, hosted application
createWindowReceiver({}).subscribe((event) => {
  if (event.type === 'service.register') {
    // Do something when a new machine is started
  } else if (event.type === 'service.stop') {
    // Do something when a machine enters a terminal state
  } else if (event.type === 'service.event') {
    // Do something when a machine receives an event
  } else if (event.type === 'service.state') {
    // Do something when a machine enters to a new state
    // Note: Does not handle transitional states.
  }
});
```

---

### Overview (`packages/xstate-react/README.md`)

# @xstate/react

This package contains utilities for using [XState](https://github.com/statelyai/xstate) with [React](https://github.com/facebook/react/).

- [Read the full documentation in the XState docs](https://stately.ai/docs/xstate-react).
- [Read our contribution guidelines](https://github.com/statelyai/xstate/blob/main/CONTRIBUTING.md).

## Quick start

1. Install `xstate` and `@xstate/react`:

```bash
npm i xstate @xstate/react
```

2. Import the `useMachine` hook:

```tsx
import { useMachine } from '@xstate/react';
import { createMachine } from 'xstate';

const toggleMachine = createMachine({
  id: 'toggle',
  initial: 'inactive',
  states: {
    inactive: {
      on: { TOGGLE: 'active' }
    },
    active: {
      on: { TOGGLE: 'inactive' }
    }
  }
});

export const Toggler = () => {
  const [state, send] = useMachine(toggleMachine);

  return (
    <button onClick={() => send({ type: 'TOGGLE' })}>
      {state.value === 'inactive'
        ? 'Click to activate'
        : 'Active! Click to deactivate'}
    </button>
  );
};
```

---

### Overview (`packages/xstate-solid/README.md`)

# @xstate/solid

The [@xstate/solid package](https://github.com/statelyai/xstate/tree/main/packages/xstate-solid) contains utilities for using [XState](https://github.com/statelyai/xstate) with [SolidJS](https://github.com/solidjs/solid).

[[toc]]

## Quick Start

1. Install `xstate` and `@xstate/solid`:

```bash
npm i xstate @xstate/solid
```

2. Import the `useActor` hook:

```js
import { useActor } from '@xstate/solid';
import { createMachine } from 'xstate';

const toggleMachine = createMachine({
  id: 'toggle',
  initial: 'inactive',
  states: {
    inactive: {
      on: { TOGGLE: 'active' }
    },
    active: {
      on: { TOGGLE: 'inactive' }
    }
  }
});

export const Toggler = () => {
  const [snapshot, send] = useActor(toggleMachine);

  return (
    <button onclick={() => send({ type: 'TOGGLE' })}>
      {snapshot.value === 'inactive'
        ? 'Click to activate'
        : 'Active! Click to deactivate'}
    </button>
  );
};
```

## API

### `useActor(logic, options?)`

A SolidJS hook that interprets the given `logic` and starts an actor that runs for the lifetime of the component.

**Arguments**

- `logic`

  ```js
  // existing machine
  const [snapshot, send] = useMachine(machine);
  ```

**Returns** a tuple of `[snapshot, send, actorRef]`:

- `snapshot` - Represents the current snapshot of the logic. This is a read-only value that is tracked by SolidJS for granular reactivity.
- `send` - A function that sends events to the running service.
- `actorRef` - The created service.

### `fromActorRef(actorRf)`

A SolidJS hook that subscribes to emitted changes from an existing [actor](https://xstate.js.org/docs/guides/actors.html).

**Arguments**

- `actorRef` - an actor object that contains `.send(...)` and `.subscribe(...)` methods. Allows [SolidJS Signal](https://www.solidjs.com/docs/latest/api#createsignal) (or function) to dynamically specify an actor.

```js
const snapshot = fromActorRef(someSpawnedActor);
```

### `useActorRef(logic, options?)`

A SolidJS hook that returns the `actorRef` created from the `logic` with the `options`, if specified. It starts the actor and runs it for the lifetime of the component. This is similar to `useActor`.

`createService` returns a static reference (to just the interpreted logic) which will not rerender when its snapshot changes.

**Arguments**

- `logic`
- `options` (optional) - [Actor options](https://xstate.js.org/docs/guides/interpretation.html#options)

```js
import { useActorRef } from '@xstate/solid';
import { someMachine } from '../path/to/someMachine';

const App = () => {
  const actorRef = useActorRef(someMachine);

  // ...
};
```

With options:

```js
// ...

const App = () => {
  const service = useActorRef(someMachine, {
    input: {/* ... */}
  });

  // ...
};
```

## Matching States

When using [hierarchical](https://xstate.js.org/docs/guides/hierarchical.html) and [parallel](https://xstate.js.org/docs/guides/parallel.html) machines, the state values will be objects, not strings. In this case, it is best to use [`state.matches(...)`](https://xstate.js.org/docs/guides/states.html#state-methods-and-getters).

The SolidJS [Switch and Match Components](<>) are ideal for this use case:

```jsx
const Loader = () => {
  const [snapshot, send] = useActor(/* ... */);

  return (
    <div>
      <Switch fallback={null}>
        <Match when={snapshot.matches('idle')}>
          <Loader.Idle />
        </Match>
        <Match when={snapshot.matches({ loading: 'user' })}>
          <Loader.LoadingUser />
        </Match>
        <Match when={snapshot.matches({ loading: 'friends' })}>
          <Loader.LoadingFriends />
        </Match>
      </Switch>
    </div>
  );
};
```

## Persisted and Rehydrated State

You can persist and rehydrate state with `useActor(...)` via `options.snapshot`:

```js
// ...

// Get the persisted state config object from somewhere, e.g. localStorage
const persistedSnapshot = JSON.parse(localStorage.getItem('some-persisted-state-key')) || someMachine.initialState;

const App = () => {
  const [snapshot, send] = useActor(someMachine, {
    snapshot: persistedSnapshot
  });

  // snapshot will rehydrate the provided persisted snapshot, it won't be the machine's initial snapshot

  return (/* ... */)
}
```

## Actor refs

The `actorRef` created in `useActor(logic)` can be referenced as the third returned value:

```js
//                  vvvvvvv
const [snapshot, send, actorRef] = useActor(someMachine);
```

You can subscribe to that `actorRef`'s snapshot changes with the [`createEffect` hook](https://www.solidjs.com/docs/latest/api#createeffect):

```js
// ...

createEffect(() => {
  const subscription = actorRef.subscribe((snapshot) => {
    // simple snapshot logging
    console.log(snapshot);
  });

  onCleanup(() => subscription.unsubscribe());
}); // note: service should never change
```

---

### Overview (`packages/xstate-store-angular/README.md`)

# @xstate/store-angular

Angular adapter for [@xstate/store](https://stately.ai/docs/xstate-store).

## Installation

```bash
npm install @xstate/store-angular
```

## Quickstart

```ts
import { Component } from '@angular/core';
import { createStore, injectStore } from '@xstate/store-angular';
// ...

const store = createStore({
  context: { count: 0 },
  on: {
    inc: (ctx) => ({ ...ctx, count: ctx.count + 1 })
  }
});

@Component({
  selector: 'app-counter',
  template: `
    <button (click)="store.send({ type: 'inc' })">Count: {{ count() }}</button>
  `
})
export class CounterComponent {
  store = store;
  count = injectStore(store, (s) => s.context.count);
}
```

## API

### `injectStore(store, selector?, compare?)`

An Angular function that creates a signal subscribed to a store, selecting a value via an optional selector function.

```ts
import { Component } from '@angular/core';
import { createStore, injectStore } from '@xstate/store-angular';
// ...

const store = createStore({
  context: { count: 0 },
  on: {
    inc: (ctx) => ({ ...ctx, count: ctx.count + 1 })
  }
});

@Component({
  selector: 'app-counter',
  template: `<div>{{ count() }}</div>`
})
export class CounterComponent {
  count = injectStore(store, (s) => s.context.count);
  // or without selector (returns full snapshot)
  snapshot = injectStore(store);
}
```

**Arguments:**

- `store` - Store created with `createStore()`
- `selector?` - Function to select a value from snapshot
- `compare?` - Equality function (default: `===`)

**Returns:** Readonly Angular signal of the selected value

---

## Re-exports

All exports from `@xstate/store` are re-exported, including `createStore`, `createAtom`, and more.

See the [XState Store docs](https://stately.ai/docs/xstate-store) for the full API, and the [Angular-specific docs](https://stately.ai/docs/xstate-store#angular) for more Angular examples.

---

### Overview (`packages/xstate-store-preact/README.md`)

# @xstate/store-preact

Preact adapter for [@xstate/store](https://stately.ai/docs/xstate-store).

## Installation

```bash
npm install @xstate/store-preact
```

## Quickstart

```tsx
import { createStore, useSelector } from '@xstate/store-preact';
// ...

const store = createStore({
  context: { count: 0 },
  on: {
    inc: (ctx) => ({ ...ctx, count: ctx.count + 1 })
  }
});

const App = () => {
  const count = useSelector(store, (s) => s.context.count);

  return (
    <button onClick={() => store.send({ type: 'inc' })}>Count: {count}</button>
  );
};
```

## API

### `useSelector(store, selector?, compare?)`

Subscribes to a store and returns a selected value.

```tsx
import { createStore, useSelector } from '@xstate/store-preact';
// ...

const store = createStore({
  context: { count: 0 },
  on: {
    inc: (ctx) => ({ ...ctx, count: ctx.count + 1 })
  }
});

const App = () => {
  const count = useSelector(store, (s) => s.context.count);
  // or without selector (returns full snapshot)
  const snapshot = useSelector(store);
  // ...
};
```

**Arguments:**

- `store` - Store created with `createStore()`
- `selector?` - Function to select a value from snapshot
- `compare?` - Equality function (default: `===`)

**Returns:** Selected value (re-renders on change)

---

## Re-exports

All exports from `@xstate/store` are re-exported, including `createStore`, `createAtom`, and more.

See the [XState Store docs](https://stately.ai/docs/xstate-store) for the full API, and the [Preact-specific docs](https://stately.ai/docs/xstate-store#preact) for more Preact examples.

---

### Overview (`packages/xstate-store-react/README.md`)

# @xstate/store-react

React adapter for [@xstate/store](https://stately.ai/docs/xstate-store).

## Installation

```bash
npm install @xstate/store-react
```

## Quickstart

```tsx
import { createStore, useSelector } from '@xstate/store-react';
// ...

const store = createStore({
  context: { count: 0 },
  on: {
    inc: (ctx) => ({ ...ctx, count: ctx.count + 1 })
  }
});

const App = () => {
  const count = useSelector(store, (s) => s.context.count);

  return (
    <button onClick={() => store.send({ type: 'inc' })}>Count: {count}</button>
  );
};
```

## API


### `useSelector(store, selector?, compare?)`

Subscribes to a store and returns a selected value.

```tsx
import { createStore, useSelector } from '@xstate/store-react';
// ...

const store = createStore({
  context: { count: 0 },
  on: {
    inc: (ctx) => ({ ...ctx, count: ctx.count + 1 })
  }
});

const App = () => {
  const count = useSelector(store, (s) => s.context.count);
  // or without selector (returns full snapshot)
  const snapshot = useSelector(store);
  // ...
};
```

**Arguments:**

- `store` - Store or other readable value created with `createStore()`
- `selector?` - Function to select a value from snapshot
- `compare?` - Equality function (default: `===`). Also applies to the full snapshot when `selector` is `undefined`.

**Returns:** Selected value (re-renders on change)

---



### `useStore(definition, options?)`

Creates a store instance scoped to a component.

```tsx
import { useStore, useSelector } from '@xstate/store-react';
// ...

const App = () => {
  const store = useStore({
    context: { count: 0 },
    on: {
      inc: (ctx) => ({ ...ctx, count: ctx.count + 1 })
    }
  });

  const count = useSelector(store, (s) => s.context.count);
  // ...
};
```

To wire up an inspector, pass the `inspect` option. The inspector is subscribed while the option is provided and unsubscribed when it is removed or the component unmounts:

```tsx
const store = useStore(
  {
    context: { count: 0 },
    on: {
      inc: (ctx) => ({ ...ctx, count: ctx.count + 1 })
    }
  },
  { inspect: inspector.inspect }
);
```

**Arguments:**

- `definition` - Store configuration object, or store logic created with `createStoreLogic()` (followed by its `input`)
- `options?` - Options object:
  - `inspect?` - Observer or callback that receives [inspection events](https://stately.ai/docs/inspection) from the store

**Returns:** Store instance (stable across re-renders)

---

### `useAtom(atom, selector?, compare?)`

Subscribes to an atom and returns its value.

```tsx
import { createAtom, useAtom } from '@xstate/store-react';
// ...

const countAtom = createAtom(0);

const App = () => {
  const count = useAtom(countAtom);

  return <button onClick={() => countAtom.set((c) => c + 1)}>{count}</button>;
};
```

**Arguments:**

- `atom` - Atom created with `createAtom()`
- `selector?` - Selector function
- `compare?` - Equality function

**Returns:** Atom value (re-renders on change)

---

### `createStoreHook(definition)`

Creates a custom hook that returns `[selectedValue, store]`.

```tsx
import { createStoreHook } from '@xstate/store-react';
// ...

const useCountStore = createStoreHook({
  context: { count: 0 },
  on: {
    inc: (ctx, e: { by: number }) => ({ ...ctx, count: ctx.count + e.by })
  }
});

const App = () => {
  const [count, store] = useCountStore((s) => s.context.count);

  return <button onClick={() => store.trigger.inc({ by: 1 })}>{count}</button>;
};
```

**Arguments:**

- `definition` - Store configuration object

**Returns:** Custom hook function

---

## Re-exports

All exports from `@xstate/store` are re-exported, including `createStore`, `createAtom`, and more.

See the [XState Store docs](https://stately.ai/docs/xstate-store) for the full API, and the [React-specific docs](https://stately.ai/docs/xstate-store#react) for more React examples.

---

### Overview (`packages/xstate-store-solid/README.md`)

# @xstate/store-solid

Solid.js adapter for [@xstate/store](https://stately.ai/docs/xstate-store).

## Installation

```bash
npm install @xstate/store-solid
```

## Quickstart

```tsx
import { createStore, useSelector } from '@xstate/store-solid';
// ...

const store = createStore({
  context: { count: 0 },
  on: {
    inc: (ctx) => ({ ...ctx, count: ctx.count + 1 })
  }
});

const App = () => {
  const count = useSelector(store, (s) => s.context.count);

  return (
    <button onClick={() => store.send({ type: 'inc' })}>
      Count: {count()}
    </button>
  );
};
```

## API


### `useSelector(store, selector, compare?)`

The accessor reconciles updates made during component setup before its subscription starts.

Creates a signal that subscribes to a store and returns a selected value.

```tsx
import { createStore, useSelector } from '@xstate/store-solid';
// ...

const store = createStore({
  context: { count: 0 },
  on: {
    inc: (ctx) => ({ ...ctx, count: ctx.count + 1 })
  }
});

const App = () => {
  const count = useSelector(store, (s) => s.context.count);

  return <div>{count()}</div>;
};
```

**Arguments:**

- `store` - Store created with `createStore()`
- `selector` - Function to select a value from snapshot
- `compare?` - Equality function (default: `===`)

**Returns:** Read-only signal of the selected value

`useSelector` works with the store's readable snapshot interface, while store-specific code can still use `store.getSnapshot()` directly.

---

## Re-exports

All exports from `@xstate/store` are re-exported, including `createStore`, `createAtom`, and more.

See the [XState Store docs](https://stately.ai/docs/xstate-store) for the full API, and the [Solid-specific docs](https://stately.ai/docs/xstate-store#solid) for more Solid examples.

---

### Overview (`packages/xstate-store-svelte/README.md`)

# @xstate/store-svelte

Svelte adapter for [@xstate/store](https://stately.ai/docs/xstate-store).

## Installation

```bash
npm install @xstate/store-svelte
```

## Quickstart

```svelte
<script>
import { createStore, useSelector } from '@xstate/store-svelte';
// ...

const store = createStore({
  context: { count: 0 },
  on: {
    inc: (ctx) => ({ ...ctx, count: ctx.count + 1 })
  }
});

const count = useSelector(store, (s) => s.context.count);
</script>

<button on:click={() => store.send({ type: 'inc' })}>
  Count: {$count}
</button>
```

## API

### `useSelector(store, selector?, compare?)`

Creates a Svelte readable store that subscribes to an XState store and returns a selected value.

```svelte
<script>
import { createStore, useSelector } from '@xstate/store-svelte';
// ...

const store = createStore({
  context: { count: 0 },
  on: {
    inc: (ctx) => ({ ...ctx, count: ctx.count + 1 })
  }
});

const count = useSelector(store, (s) => s.context.count);
// or without selector (returns full snapshot)
const snapshot = useSelector(store);
</script>

<div>{$count}</div>
```

**Arguments:**

- `store` - Store created with `createStore()`
- `selector?` - Function to select a value from snapshot
- `compare?` - Equality function (default: `===`)

**Returns:** Svelte readable store

---

## Re-exports

All exports from `@xstate/store` are re-exported, including `createStore`, `createAtom`, and more.

See the [XState Store docs](https://stately.ai/docs/xstate-store) for the full API, and the [Svelte-specific docs](https://stately.ai/docs/xstate-store#svelte) for more Svelte examples.

---

### Overview (`packages/xstate-store-vue/README.md`)

# @xstate/store-vue

Vue adapter for [@xstate/store](https://stately.ai/docs/xstate-store).

## Installation

```bash
npm install @xstate/store-vue
```

## Quickstart

```vue
<script setup>
import { createStore, useSelector } from '@xstate/store-vue';
// ...

const store = createStore({
  context: { count: 0 },
  on: {
    inc: (ctx) => ({ ...ctx, count: ctx.count + 1 })
  }
});

const count = useSelector(store, (s) => s.context.count);
</script>

<template>
  <button @click="store.send({ type: 'inc' })">Count: {{ count }}</button>
</template>
```

## API

### `useSelector(store, selector?, compare?)`

A composable that subscribes to a store and returns a selected value as a readonly ref.

```vue
<script setup>
import { createStore, useSelector } from '@xstate/store-vue';
// ...

const store = createStore({
  context: { count: 0 },
  on: {
    inc: (ctx) => ({ ...ctx, count: ctx.count + 1 })
  }
});

const count = useSelector(store, (s) => s.context.count);
// or without selector (returns full snapshot)
const snapshot = useSelector(store);
</script>

<template>
  <div>{{ count }}</div>
</template>
```

**Arguments:**

- `store` - Store or other readable value created with `createStore()`
- `selector?` - Function to select a value from snapshot
- `compare?` - Equality function (default: `===`)

**Returns:** Readonly ref of the selected value

---

## Re-exports

All exports from `@xstate/store` are re-exported, including `createStore`, `createAtom`, and more.

See the [XState Store docs](https://stately.ai/docs/xstate-store) for the full API, and the [Vue-specific docs](https://stately.ai/docs/xstate-store#vue) for more Vue examples.

---

### Overview (`packages/xstate-store/README.md`)

# `@xstate/store`

XState Store is a library for **simple event-based state management**. If you want a state management library that allows you to update a store's state via events, `@xstate/store` is a great option. If you need more complex application logic needs, like state machines/statecharts, effects, communicating actors, and more, consider [using XState instead](https://github.com/statelyai/xstate).



- **Extremely simple**: transitions update state via events, just like Redux, Zustand, Pinia, etc.
- **Small**: no required runtime dependencies
- **XState compatible**: use it with (or without) XState, or convert to XState machines when you need to handle more complex logic & effects.
- **Extra type-safe**: great typing out of the box, with strong inference and no awkwardness.

> [!NOTE]
> This readme is written for [TypeScript](#typescript) users. If you are a JavaScript user, just remove the types.

## Installation

```bash
# yarn add @xstate/store
# pnpm add @xstate/store
npm install @xstate/store
```

## Quick start

```ts
import { createStore } from '@xstate/store';

export const donutStore = createStore({
  context: {
    donuts: 0,
    favoriteFlavor: 'chocolate'
  },
  on: {
    addDonut: (context) => ({
      ...context,
      donuts: context.donuts + 1
    }),
    changeFlavor: (context, event: { flavor: string }) => ({
      ...context,
      favoriteFlavor: event.flavor
    }),
    eatAllDonuts: (context) => ({
      ...context,
      donuts: 0
    })
  }
});

donutStore.subscribe((snapshot) => {
  console.log(snapshot.context);
});

// Equivalent to
// donutStore.send({ type: 'addDonut' });
donutStore.trigger.addDonut();
// => { donuts: 1, favoriteFlavor: 'chocolate' }

// donutStore.send({
//   type: 'changeFlavor',
//   flavor: 'strawberry' // Strongly-typed!
// });
donutStore.trigger.changeFlavor({ flavor: 'strawberry' });
// => { donuts: 1, favoriteFlavor: 'strawberry' }
```

## Checking events



Use `store.can` to check whether an event is allowed without updating the store:

```ts
const store = createStore({
  context: { count: 0 },
  on: {
    increment: (context, event: { by: number }) => {
      if (context.count + event.by > 10) {
        return;
      }

      return {
        count: context.count + event.by
      };
    }
  }
});

store.can.increment({ by: 4 });
// => true
```

Returning `undefined` marks the event as not allowed. Returning the same context
object is still allowed, and transitions that enqueue effects are allowed.

## Persistence



Use the `persist` extension to save state after events are committed. Calling
`store.can` or the pure `store.transition` method does not schedule writes.
Writes preserve commit order, including events triggered synchronously by effects
or subscriptions. A newer eligible event can supersede an older pending write;
`onDone` runs for writes actually performed. Asynchronous writes execute in event
order for each store. Call
`await flushStorage(store)` to write buffered changes and wait for queued writes
to finish. Synchronous storage adapters continue to write synchronously.

With throttling, `pick` runs once per write on the latest buffered context.
`clearStorage(store)` cancels buffered writes and removes saved data after any
already queued writes finish; await its result when using asynchronous storage.
New events sent after clearing can persist new state. For asynchronous storage,
call `await rehydrateStore(store)` to load saved state; initial read failures are
reported through `onError`.

```ts
import { persist, flushStorage } from '@xstate/store/persist';

const savedDonutStore = donutStore.with(persist({ name: 'donuts' }));
savedDonutStore.trigger.addDonut();
await flushStorage(savedDonutStore);
```

### Undo and persistence



Snapshot-based `undoRedo` restores historical state while preserving live
extension metadata, including persistence hydration. A custom `restore` callback
can enqueue events; their updated extension metadata is preserved too. Apply
`persist` after `undoRedo` when undo and redo themselves should write to storage:

```ts
import { undoRedo } from '@xstate/store/undo';

const undoableDonutStore = donutStore
  .with(undoRedo({ strategy: 'snapshot' }))
  .with(persist({ name: 'undoable-donuts' }));
```

## Atom updates and subscriptions



Reads inside a writable atom's `set(previous => next)` updater do not create
reactive dependencies. Use a computed atom getter to track other atoms instead.
If a synchronous subscriber throws, other queued subscribers still receive their
notifications before the first error is rethrown to the caller. The atom's value
has already changed; later updates continue to notify subscribers normally.

## Source atoms



Use `createSourceAtom` for a read-only external value. Direct and derived
subscribers share one listener; cleanup runs synchronously when the last consumer
leaves. Plain reads do not start listeners. Resubscribing reconnects and refreshes
the snapshot.

```ts
import { createAtom, createSourceAtom } from '@xstate/store';

const media = window.matchMedia('(prefers-color-scheme: dark)');
const isDark = createSourceAtom({
  getSnapshot: () => media.matches,
  subscribe: (notify) => {
    media.addEventListener('change', notify);
    return () => media.removeEventListener('change', notify);
  }
});
const theme = createAtom(() => (isDark.get() ? 'dark' : 'light'));
const subscription = theme.subscribe(console.log);
subscription.unsubscribe(); // Removes the media query listener.
```

See [source atoms](./docs/source-atoms.md) for snapshot comparison, conditional
dependencies, and lifecycle timing. Use XState actors for commands, retries, or
reconnection logic.

## Async atoms



`createAsyncAtom` loads a value lazily and exposes a `pending`, `done`, or
`error` state. Atoms read synchronously by its getter remain dependencies after
the request succeeds or fails. When a dependency changes, subscribed async atoms
reload; otherwise, they reload on the next read. Read dependencies before the
first `await` to track them. Errors while delivering a resolved value (including
source activation) also become the async atom’s `error` state. If notifying that
error state fails, the state remains available through `.get()`.

```ts
import { createAtom, createAsyncAtom } from '@xstate/store';

const userId = createAtom('ada');
const user = createAsyncAtom(async ({ signal }) => {
  const id = userId.get();
  const response = await fetch(`/users/${id}`, { signal });
  return response.json();
});

user.subscribe((state) => {
  if (state.status === 'done') {
    console.log(state.data);
  }
});

userId.set('grace'); // Reloads even after the previous request settled.
```

Recomputing aborts the previous getter's signal and ignores its stale result.

## Usage with React

Import `useSelector` from `@xstate/store-react`. Select the data you want via `useSelector(…)` and send events using `store.send(eventObject)`:

```tsx
import { donutStore } from './donutStore.ts';
import { useSelector } from '@xstate/store-react';

function DonutCounter() {
  const donutCount = useSelector(donutStore, (state) => state.context.donuts);

  return (
    <div>
      <button onClick={() => donutStore.send({ type: 'addDonut' })}>
        Add donut ({donutCount})
      </button>
    </div>
  );
}
```

## Usage with SolidJS

Import `useSelector` from `@xstate/store-solid`. Select the data you want via `useSelector(…)` and send events using `store.send(eventObject)`:

```tsx
import { donutStore } from './donutStore.ts';
import { useSelector } from '@xstate/store-solid';

function DonutCounter() {
  const donutCount = useSelector(donutStore, (state) => state.context.donuts);

  return (
    <div>
      <button onClick={() => donutStore.send({ type: 'addDonut' })}>
        Add donut ({donutCount()})
      </button>
    </div>
  );
}
```

## Usage with Immer

XState Store works well with immutable update libraries like [Immer](https://github.com/immerjs/immer) or [Mutative](https://github.com/unadlib/mutative). Use `produce(...)` inside your transition functions:

```ts
import { createStore } from '@xstate/store';
import { produce } from 'immer'; // or { create } from 'mutative'

const donutStore = createStore({
  context: {
    donuts: 0,
    favoriteFlavor: 'chocolate'
  },
  on: {
    addDonut: (context) =>
      produce(context, (draft) => {
        draft.donuts++;
      }),
    changeFlavor: (context, event: { flavor: string }) =>
      produce(context, (draft) => {
        draft.favoriteFlavor = event.flavor;
      }),
    eatAllDonuts: (context) =>
      produce(context, (draft) => {
        draft.donuts = 0;
      })
  }
});
```

If a transition should be unavailable, return `undefined` from the transition
before calling `produce(...)`:

```ts
on: {
  eatDonut: (context) => {
    if (context.donuts === 0) {
      return;
    }

    return produce(context, (draft) => {
      draft.donuts--;
    });
  };
}
```

Immer treats a producer that returns `undefined` the same as a producer that
does not explicitly return anything. If you need `produce(...)` itself to return
`undefined`, return Immer's `nothing` token from the producer:

```ts
import { nothing, produce } from 'immer';

on: {
  eatDonut: (context) =>
    produce(context, (draft) => {
      if (draft.donuts === 0) {
        return nothing;
      }

      draft.donuts--;
    });
}
```

## TypeScript

XState Store is written in TypeScript and provides full type safety, _without_ you having to specify generic type parameters. The `context` type is inferred from the initial context object, and the event types are inferred from the event object payloads you provide in the transition functions.

```ts
import { createStore } from '@xstate/store';

const donutStore = createStore({
  // Context inferred as:
  // {
  //   donuts: number;
  //   favoriteFlavor: string;
  // }
  context: {
    donuts: 0,
    favoriteFlavor: 'chocolate'
  },
  on: {
    // Event inferred as:
    // {
    //   type: 'changeFlavor';
    //   flavor: string;
    // }
    changeFlavor: (context, event: { flavor: string }) => {
      context.favoriteFlavor = event.flavor;
    }
  }
});

donutStore.getSnapshot().context.favoriteFlavor; // string
donutStore.get().context.favoriteFlavor; // same snapshot, readable/tracked read

donutStore.send({
  type: 'changeFlavor', // Strongly-typed from transition key
  flavor: 'strawberry' // Strongly-typed from { flavor: string }
});
```

If you want to provide event or emitted-event types explicitly, you can use `schemas` with any library that implements the [Standard Schema](https://standardschema.dev/) interface. Schemas define the store's runtime-readable contract: the shape of its context, accepted events, and emitted events. Store uses schemas for type inference and metadata by default; it does not validate schema-declared values unless you opt in with `validateSchemas()`.

```ts
import { createStore } from '@xstate/store';
import { z } from 'zod';

const store = createStore({
  schemas: {
    context: z.object({
      donuts: z.number(),
      favoriteFlavor: z.string()
    }),
    events: {
      changeFlavor: z.object({
        flavor: z.string()
      })
    },
    emitted: {
      flavorChanged: z.object({
        flavor: z.string()
      })
    }
  },
  context: {
    donuts: 0,
    favoriteFlavor: 'chocolate'
  },
  on: {
    changeFlavor: (context, event, enqueue) => {
      enqueue.emit.flavorChanged({ flavor: event.flavor });
      return {
        ...context,
        favoriteFlavor: event.flavor
      };
    }
  }
});
```

Event and emitted-event schemas describe payload objects. Use an empty object
schema for events without payload:

```ts
schemas: {
  events: {
    reset: z.object({})
  },
  emitted: {
    reset: z.object({})
  }
}
```

### Validating schemas

Use the `validateSchemas()` extension when the store should validate its schema
contract at runtime:

```ts
import { createStore } from '@xstate/store';
import { validateSchemas } from '@xstate/store/validate';
import { z } from 'zod';

const store = createStore({
  schemas: {
    context: z.object({
      count: z.number()
    }),
    events: {
      increment: z.object({
        by: z.number()
      })
    },
    emitted: {
      increased: z.object({
        by: z.number()
      })
    }
  },
  context: { count: 0 },
  on: {
    increment: (context, event, enqueue) => {
      enqueue.emit.increased({ by: event.by });
      return { count: context.count + event.by };
    }
  }
}).with(validateSchemas());
```

`validateSchemas()` validates store macrosteps. It validates the event sent to
the store, the final context after the transition completes, and emitted events
before any effects execute. Events queued internally with `enqueue.trigger` are
processed as part of the same macrostep; their payloads are not separately
validated in this version.

Invalid `send(...)`, `trigger.*(...)`, or `transition(...)` calls throw a
`StoreValidationError`. `store.can.*(...)` always returns a boolean; validation
errors make it return `false`.

By default, unknown events and emitted events throw when the corresponding
schema map exists. Extension-added event types are treated as known, even when
they do not have payload schemas. You can opt out:

```ts
const store = createStore({
  // ...
}).with(
  validateSchemas({
    unknownEvents: 'ignore',
    unknownEmitted: 'ignore'
  })
);
```

Use `store.getSnapshot()` when you want an explicit snapshot read from the store itself. Use `store.get()` when consuming the store as a `Readable` value in tracked or reactive code.

If you want to make the `context` type more specific, you can strongly type the `context` outside of `createStore(…)` and pass it in:

```ts
import { createStore } from '@xstate/store';

interface DonutContext {
  donuts: number;
  favoriteFlavor: 'chocolate' | 'strawberry' | 'blueberry';
}

const donutContext: DonutContext = {
  donuts: 0,
  favoriteFlavor: 'chocolate'
};

const donutStore = createStore({
  context: donutContext,
  on: {
    // ... (transitions go here)
  }
});
```

## Effects and Side Effects

You can enqueue effects in state transitions using the `enqueue` argument:

```ts
import { createStore } from '@xstate/store';

const store = createStore({
  context: { count: 0 },
  on: {
    incrementDelayed: (context, event, enqueue) => {
      enqueue.effect(async () => {
        await new Promise((resolve) => setTimeout(resolve, 1000));
        store.send({ type: 'increment' });
      });

      return context;
    },
    increment: (context) => ({
      ...context,
      count: context.count + 1
    })
  }
});
```

## Emitting Events

You can emit events from transitions by declaring them in `schemas.emitted` and using `enqueue.emit`:

```ts
import { createStore } from '@xstate/store';
import { z } from 'zod';

const store = createStore({
  schemas: {
    emitted: {
      increased: z.object({
        by: z.number()
      })
    }
  },
  context: { count: 0 },
  on: {
    inc: (context, event: { by: number }, enqueue) => {
      enqueue.emit.increased({ by: event.by });

      return {
        ...context,
        count: context.count + event.by
      };
    }
  }
});

// Listen for emitted events
store.on('increased', (event) => {
  console.log(`Count increased by ${event.by}`);
});
```

---

### Overview (`packages/xstate-svelte/README.md`)

# @xstate/svelte

This package contains utilities for using [XState](https://github.com/statelyai/xstate) with [Svelte](https://github.com/sveltejs/svelte).

- [Read the full documentation in the XState docs](https://stately.ai/docs/xstate-svelte).
- [Read our contribution guidelines](https://github.com/statelyai/xstate/blob/main/CONTRIBUTING.md).

## Quick Start

1. Install `xstate` and `@xstate/svelte`:

```bash
npm i xstate @xstate/svelte
```

**Via CDN**

```html
<script src="https://unpkg.com/@xstate/svelte/dist/xstate-svelte.min.js"></script>
```

By using the global variable `XStateSvelte`

2. Import `useMachine`

```svelte
<script>
  import { useMachine } from '@xstate/svelte';
  import { createMachine } from 'xstate';

  const toggleMachine = createMachine({
    id: 'toggle',
    initial: 'inactive',
    states: {
      inactive: {
        on: { TOGGLE: 'active' }
      },
      active: {
        on: { TOGGLE: 'inactive' }
      }
    }
  });

  const { state, send } = useMachine(toggleMachine);
</script>

<button on:click={() => send('TOGGLE')}>
  {$state.value === 'inactive'
    ? 'Click to activate'
    : 'Active! Click to deactivate'}
</button>
```

---

### Overview (`packages/xstate-vue/README.md`)

# @xstate/vue

This package contains utilities for using [XState](https://github.com/statelyai/xstate) with [Vue](https://github.com/vuejs/vue).

- [Read the full documentation in the XState docs](https://stately.ai/docs/xstate-vue).
- [Read our contribution guidelines](https://github.com/statelyai/xstate/blob/main/CONTRIBUTING.md).

## :warning: Vue 2 Notice:

If you're using Vue 2.x, please see [the Vue recipe](https://xstate.js.org/docs/recipes/vue.html) instead, or use the [`xstate-vue2` package](https://github.com/ChrisShank/xstate-vue2) if you want to use the Vue Composition API.

## Quick start

1. Install `xstate` and `@xstate/vue`:

```bash
npm i xstate @xstate/vue
```

**Via CDN**

```html
<script src="https://unpkg.com/@xstate/vue/dist/xstate-vue.min.js"></script>
```

By using the global variable `XStateVue`

2. Import the `useMachine` composition function:

```vue
<script setup>
import { useMachine } from '@xstate/vue';
import { createMachine } from 'xstate';

const toggleMachine = createMachine({
  id: 'toggle',
  initial: 'inactive',
  states: {
    inactive: {
      on: { TOGGLE: 'active' }
    },
    active: {
      on: { TOGGLE: 'inactive' }
    }
  }
});

const { snapshot, send } = useMachine(toggleMachine);
</script>

<template>
  <button @click="send({ type: 'TOGGLE' })">
    {{
      snapshot.value === 'inactive'
        ? 'Click to activate'
        : 'Active! Click to deactivate'
    }}
  </button>
</template>
```

---

### Overview (`templates/react-ts/README.md`)

# XState React TypeScript template

A starting point template for using XState with React and TypeScript. Create a feedback form using a simple state machine.

Using [Vite](https://vitejs.dev/) as a build tool and to run the local development server.

## [➡️ Open in CodeSandbox](https://codesandbox.io/p/sandbox/github/statelyai/xstate/tree/main/templates/react-ts?file=%2Fsrc%2FfeedbackMachine.ts)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/templates/react-ts?file=%2Fsrc%2FfeedbackMachine.ts)

---

### Overview (`templates/svelte-ts/README.md`)

# XState Svelte TypeScript template

A starting point template for using XState with [Svelte](https://svelte.dev) and TypeScript. Create a feedback form using a simple state machine.

Using [Vite](https://vitejs.dev/) as a build tool and to run the local development server.

## [➡️ Open in CodeSandbox](https://codesandbox.io/p/sandbox/github/statelyai/xstate/tree/main/templates/svelte-ts?file=%2Fsrc%2FfeedbackMachine.ts)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/templates/svelte-ts?file=%2Fsrc%2FfeedbackMachine.ts)

---

### Overview (`templates/vanilla-ts/README.md`)

# XState TypeScript template

A starting point template for using XState with TypeScript. Create feedback form logic using a simple state machine.

Using [Vite](https://vitejs.dev/) as a build tool and to run the local development server.

## [➡️ Open in CodeSandbox](https://codesandbox.io/p/sandbox/github/statelyai/xstate/tree/main/templates/vanilla-ts?file=%2Fsrc%2FfeedbackMachine.ts)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/templates/vanilla-ts?file=%2Fsrc%2FfeedbackMachine.ts)

---

### Overview (`templates/vue-ts/README.md`)

# XState Vue TypeScript template

A starting point template for using XState with Vue and TypeScript. Create a feedback form using a simple state machine.

Using [Vite](https://vitejs.dev/) as a build tool and to run the local development server.

## [➡️ Open in CodeSandbox](https://codesandbox.io/p/sandbox/github/statelyai/xstate/tree/main/templates/vue-ts?file=%2Fsrc%2FfeedbackMachine.ts)

[](https://stackblitz.com/github/statelyai/xstate/tree/main/templates/vue-ts?file=%2Fsrc%2FfeedbackMachine.ts)

---

### Packages Xstate Store Docs Source Atoms (`packages/xstate-store/docs/source-atoms.md`)

---
title: Source atoms
description: Share external snapshot subscriptions across atom consumers.
---

Use `createSourceAtom` to expose an external value, such as a media query or a
browser observer, as a read-only atom. Provide `getSnapshot` to read its current
value and `subscribe` to attach a change listener. The listener calls `notify()`;
XState Store reads the latest snapshot. Return either a cleanup function or a
subscription object with an `unsubscribe()` method. XState Store normalizes the
adapter result internally; the atom's public `.subscribe()` always returns a
subscription object, so consumers call `subscription.unsubscribe()`.

```ts
import { createAtom, createSourceAtom } from '@xstate/store';

const media = window.matchMedia('(prefers-color-scheme: dark)');
const isDark = createSourceAtom({
  getSnapshot: () => media.matches,
  subscribe: (notify) => {
    media.addEventListener('change', notify);
    return () => media.removeEventListener('change', notify);
  }
});
const theme = createAtom(() => (isDark.get() ? 'dark' : 'light'));

// Starts one media query listener, through the derived atom.
const derived = theme.subscribe((value) => console.log(value));
const direct = isDark.subscribe((value) => console.log(value));

// The direct subscriber still needs the listener.
derived.unsubscribe();
// Removes the listener synchronously.
direct.unsubscribe();
```

Create browser sources in an environment where their browser APIs are available.
For server rendering, provide a snapshot reader that works on the server; a plain
read does not attach the external listener.

## Reading and subscribing

Creation is lazy. Calling the source atom's `.get()` without a live consumer reads
`getSnapshot` without calling `subscribe`. Reading an unobserved derived atom also
does not start external subscriptions. Derived atoms cache their values; an
unobserved derived read does not poll external sources for changes.

The first direct subscription, or subscription to a derived atom that reads the
source, starts the listener. Consumers share one listener per source atom instance.
Setup occurs after dependency evaluation settles and before the outer subscription
or update call returns. XState Store attaches the listener before refreshing the
snapshot, including when registration calls `notify()` synchronously.

Like other atoms, subscribing does not emit the initial value. Call `.get()` to
read it. A snapshot change during listener registration can notify subscribers
before `subscribe()` returns.

When a conditional derived atom stops reading the source, its consumer is removed.
The listener remains active while any other direct or indirect consumer needs it.
Cleanup runs after graph updates settle, before the last `unsubscribe()` or update
call returns. Moving a dependency between derived branches during the same update
does not restart a shared listener. Separate unsubscribe/resubscribe calls do.

Subscribing again reconnects the listener and refreshes the snapshot. Notifications
from an earlier, cleaned-up listener are ignored, including after reconnection.

## Snapshot contract

`getSnapshot` should return a stable value until the external source changes, and
`subscribe` should notify whenever that value changes. Reads inside these
callbacks do not establish atom dependencies. Model reactive dependencies in a
derived atom instead.

Snapshots use `Object.is` comparison by default. Provide a custom comparator when
an external source returns a new object for an unchanged value:

```ts
const size = createSourceAtom(
  {
    getSnapshot: () => ({ width: window.innerWidth, height: window.innerHeight }),
    subscribe: (notify) => {
      window.addEventListener('resize', notify);
      return { unsubscribe: () => window.removeEventListener('resize', notify) };
    }
  },
  {
    compare: (previous, next) =>
      previous.width === next.width && previous.height === next.height
  }
);
```

Source atoms expose `.get()` and `.subscribe()`, with no `.set()` or `.send()`.
They do not provide timed retries or an error state. A failed activation with live
consumers remains eligible for another attempt on a later atom operation. It is
never retried within the failing operation. Synchronous snapshot, registration,
notification, and cleanup errors propagate to the caller. If registration fails
before returning a subscription, the adapter must release any resources it acquired.

Use XState actors when a resource needs commands, retries, reconnection backoff,
or a richer lifecycle. Adapt an actor snapshot with `getSnapshot: () =>
actor.getSnapshot()` and `subscribe: (notify) => actor.subscribe(notify)`; the
actor's owner remains responsible for starting and stopping it.

---

--- METRICS ---
- Files Extracted: 45
- Estimated Token Budget: ~25224 tokens
- Canonical Reference: https://codewiki.google/github.com/statelyai/xstate
