10 April 2026

React Flow Multiplayer: How to Add Real-Time Collaboration to a Workflow Editor with Liveblocks

Real-time collaboration is a game-changing feature for many apps. In a workflow editor, it's particularly valuable, since multiple users can work on the same workflow and see each other's changes in real time.

There's a lot that goes into building real-time collaboration from scratch. Liveblocks takes care of all of it, and it's the tool we'll be using in this article.

Real-Time Collaboration

Real-time collaboration is complex under the hood — state needs to stay in sync across all clients, conflicts need to be resolved, and connections need to be managed. Liveblocks handles all of that for you.

It gives you shared state that syncs automatically, event broadcasting, presence awareness, and ready-made libraries for common use cases like text editors, whiteboards, and diagrams.

How to Add It to a Workflow Editor

If you've followed the previous articles, you already have a workflow editor built around a workflow state, a function that receives change objects, and a function that applies those changes to the state.

function initialWorkflow(): Workflow {
  return {
    flow: {
      start: { message: "" },
      elements: [],
      dropTop: new Set(),
      end: { message: "" },
    },
    widget: null,
    active: null,
  };
}

export default function Home() {
  const [workflow, setWorkflow] = useState(() => initialWorkflow());

  const onWorkflowChange = useCallback((changes: WorkflowChange[]) => {
    setWorkflow((workflow) => applyWorkflowChanges(changes, workflow));
  }, []);

  return (
    <div className="flex h-screen flex-col bg-neutral-900">
      <WorkflowView workflow={workflow} onWorkflowChange={onWorkflowChange} />
    </div>
  );
}

To add multiplayer, we replace the local workflow state with Liveblocks storage and wrap the app in the providers needed to connect to Liveblocks and set up a shared room.

export default function Home() {
  return (
    <LiveblocksProvider publicApiKey={process.env.NEXT_PUBLIC_API_KEY!}>
      <RoomProvider
        id="workflow-kit"
        initialPresence={{ cursor: null }}
        initialStorage={{
          workflow: new LiveObject({
            flow: new LiveObject({
              start: new LiveObject({ message: "" }),
              elements: new LiveList([]),
              dropTop: new LiveMap(),
              end: new LiveObject({ message: "" }),
            }),
            widget: null,
            active: null,
            center: null,
          }),
        }}
      >
        <ClientSideSuspense fallback={<div>Loading…</div>}>
          <App />
        </ClientSideSuspense>
      </RoomProvider>
    </LiveblocksProvider>
  );
}

function App() {
  const workflow: Workflow = useStorage((root) => root.workflow);

  const onWorkflowChange = useMutation(
    ({ storage }, changes: WorkflowChange[]) => {
      const workflow = storage.get("workflow");
      applyWorkflowChanges(changes, workflow);
    },
    [],
  );

  return (
    <div className="flex h-screen flex-col bg-neutral-900">
      <WorkflowView workflow={workflow} onWorkflowChange={onWorkflowChange} />
    </div>
  );
}

As shown, the changes are minimal:

  • LiveblocksProvider: Sets up the connection to Liveblocks.
  • RoomProvider: Creates the shared room where the collaborative experience takes place.
  • useStorage: Reads the workflow from the storage, keeping it in sync across all connected users.
  • useMutation: Writes changes to the storage, ensuring they are propagated to all connected users.
React Flow Multiplayer: How to Add Real-Time Collaboration to a Workflow Editor with Liveblocks