Zustand Yjs Middleware

1.3.1 · maintenance · verified Wed Apr 22

zustand-middleware-yjs is a Zustand middleware that enables real-time collaborative state synchronization for any Zustand store using Yjs. This library, currently at stable version 1.3.1 (last updated June 2023), transforms a standard Zustand store into a Conflict-free Replicated Data Type (CRDT), ensuring state consistency across multiple peers. Its key differentiator is its ability to wrap an existing Zustand store creator, making any store collaborative without requiring special hooks or structures for shared types, in contrast to libraries like `zustand-yjs`. It integrates seamlessly with vanilla Zustand and can be composed with other Zustand middleware such as Immer or Redux, broadening its applicability across various React and non-React environments where Zustand is used. The package ships with TypeScript types, but its development appears to be in maintenance mode as of mid-2026.

Common errors

Warnings

Install

Imports

Quickstart

This example demonstrates how to integrate `zustand-middleware-yjs` with a Zustand store, creating a collaborative counter that syncs its state via a Yjs document. It showcases store creation, middleware application, and basic state updates.

import React from "react";
import { render } from "react-dom";

import * as Y from "yjs";
import create from "zustand";
import yjs from "zustand-middleware-yjs";

// Create a Y Doc to place our store in.
const ydoc = new Y.Doc();

// Create the Zustand store.
const useSharedStore = create(
  // Wrap the store creator with the Yjs middleware.
  yjs(
    // Provide the Y Doc and the name of the shared type that will be used
    // to hold the store.
    ydoc, "shared",
          
    // Create the store as you would normally.
    (set) =>
      ({
        count: 0,
        increment: () =>
          set(
            (state) =>
            ({
              count: state.count + 1,
            })
          ),
      })
  )
);

// Use the shared store like you normally would any other Zustand store.
const App = () =>
{
  const { count, increment } = useSharedStore((state) =>
    ({
      count: state.count,
      increment: state.increment
    }));

  return (
    <>
      <p>count: {count}</p>
      <button onClick={() => increment()}>+</button>
    </>
  );
};

// Assuming an HTML element with id 'app-root' exists
// e.g., <div id="app-root"></div>
// render(
//   <App />,
//   document.getElementById("app-root")
// );

// For a runnable example without DOM, we can log the state
const unsub = useSharedStore.subscribe(state => console.log('Current state:', state));
useSharedStore.getState().increment();
useSharedStore.getState().increment();
console.log('Final state after increments:', useSharedStore.getState());
unsub();

// You would typically connect ydoc to a provider (e.g., websocket) for collaboration
// import { WebsocketProvider } from 'y-websocket';
// const wsProvider = new WebsocketProvider('ws://localhost:1234', 'my-roomname', ydoc);

view raw JSON →