Skip to main content
v2.2What's new in the changelog →

Your state is a living tree.

Mutable, protected models on the inside. Snapshots, JSON patches and replayable actions on the outside. Powered by MobX, typed end to end.

Read the docs →
licensetypesCIcodecovNetlify Status
TodoStoretodos[]
ACTIONSonActionMiddleware
    PATCHESonPatches
      SNAPSHOTgetSnapshot(store)
      {
        todos: [],
        $modelType: "todo/Store"
      }

      Write plain actions. Get the rest for free.

      Getting started guide →
      YOU WRITETodo.ts
      @model("todo/Todo")
      class Todo extends Model({
        text: prop<string>(""),
        done: prop(false),
      }) {
        @modelAction
        toggle() {
          this.done = !this.done
        }
      }
      YOU GET · SNAPSHOTSgetSnapshot(todo)
      { text: "Write docs", done: true, $modelType: "todo/Todo" }
      YOU GET · TYPESSnapshotOutOf<Todo>
      { text: string; done: boolean; … }
      YOU GET · PATCHESonPatches(todo, …)
      [{ op: "replace", path: ["done"], value: true }]
      YOU GET · REPLAYABLE ACTIONSonActionMiddleware(store, …)
      { actionName: "toggle", args: [], targetPath: ["todos", 1] }
      YOU GET · UNDOundoMiddleware(store)
      undoManager.undo() // done → false
      YOU GET · RESTOREfromSnapshot(Todo, sn)
      const copy = fromSnapshot(Todo, sn)
      copy.toggle() // a live, typed Todo
      YOU GET · PROTECTIONtodo.done = true
      // throws: data changes must be performed inside model actions
      YOU GET · TREEgetParent(todo) · getRoot(todo)
      getParent(todo) // store.todos
      getRoot(todo) // store
      MIDDLEWARES

      Time travel built in

      Undo/redo, transactions, read-only guards and your own action middlewares.

      REFERENCES

      Links that stay valid

      First-class references between nodes, resolved as the tree changes.

      TYPESCRIPT

      Inferred, not declared twice

      Models, snapshots and actions typed from one definition.

      RUNTIME TYPES

      Checked when it matters

      Opt into runtime type checking per prop with tProp.

      CRDT

      Y.js & Loro bindings

      Collaborative, offline-friendly state with the same models.

      Loved by the people who use it

      It's taken all the best bits from mobx and mobx-state-tree and put them into a single package that's a joy to work with.
      @robclouthon issue #146
      After evaluating every state library out there, mobx-keystone stands out.
      @lolmauson issue #566
      mobx-keystone is awesome and way easier to use for typesafe domain modeling than MST.
      @krnsk0on issue #467