Skip to content

ryanntannn/zustand-sync

Repository files navigation

zustand-sync

Area.2025-09-28.23.21.25.mp4

A barebones middleware to sync zustand stores across multiple clients. zustand-sync uses JSON Patch (RFC 6902) under the hood to translate state changes into patches that can be sent over a transport layer.

Basic Usage

In your react project with zustand installed:

npm install @ryanntannn/zustand-sync
docker run -p 8080:8080 ryanntannn/zustand-sync-server:latest

Then, add syncStoreMiddleware to your zustand with the WebSocketTransportProvider:

import { create } from "zustand";
import { syncStoreMiddleware, WebSocketTransportProvider } from "zustand-sync";

type ExampleStore = {
  count: number;
  increment: () => void;
  decrement: () => void;
  reset: () => void;
};

export const useExampleStore = create(
  syncStoreMiddleware(
    (set) => ({
      count: 0,
      increment: () => set((state) => ({ count: state.count + 1 })),
      decrement: () => set((state) => ({ count: state.count - 1 })),
      reset: () => set({ count: 0 }),
    }),
    {
      transport: WebSocketTransportProvider<ExampleStore>({
        projectId: "your-project-id",
      }),
    }
  )
);

Roadmap

  • Basic WebSocket transport provider
  • WebSocket server with project-based routing
  • Storage providers on server (Redis, Postgres, In-memory/Disk etc.)
  • Additional transport providers (WebRTC, HTTP Long Polling etc.)
  • Authentication and Authorization
  • Conflict resolution, disaster recovery and offline support

How It Works

This sequence diagram illustrates the ideal flow of how zustand-sync works with a WebSocket transport provider:

sequenceDiagram
		actor Store
		participant syncedStoreMiddleware
		participant patchGenerator
		participant patchApplier
		participant TransportProvider
		actor OtherClient

		Store->>syncedStoreMiddleware: Create new store with syncStoreMiddleware
		syncedStoreMiddleware->>TransportProvider: Initialize transport (e.g. WebSocket)
		TransportProvider->>syncedStoreMiddleware: First message (initialState)
		syncedStoreMiddleware->>Store: set({...initialState})
		Store->>syncedStoreMiddleware: Perform state update (e.g. increment())
		syncedStoreMiddleware->>patchGenerator: generatePatch(oldState, newState)
		patchGenerator->>syncedStoreMiddleware: patch
		syncedStoreMiddleware->>TransportProvider: broadcastPatches(patch)
		TransportProvider->>OtherClient: Transmit JSON Patch
		OtherClient->>TransportProvider: Transmit JSON Patch
		TransportProvider->>syncedStoreMiddleware: onPatches(patch)
		syncedStoreMiddleware->>patchApplier: applyPatch(oldState, patch)
		patchApplier->>syncedStoreMiddleware: newState
		syncedStoreMiddleware->>Store: set(newState)
Loading

About

A simple, barebones "multiplayer" middleware for zustand

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors