TypeScript · Yjs · MobX
Local models. Shared when you need them.
Build your model with TypeScript classes, relationships, and MobX reactivity. When it joins a document, the same objects gain shared identity and Yjs synchronization. Keep working with them as usual.
Start with a complete local model #
Create objects, organize their relationships, and observe changes. Collections, parent-child relationships, and MobX reactivity all work locally, without creating a document.
import { Plexus, PlexusModel, syncing } from "@here.build/plexus";
@syncing("Task")
class Task extends PlexusModel<Project> {
@syncing accessor title = "";
@syncing accessor done = false;
}
@syncing("Project")
class Project extends PlexusModel {
@syncing.child.list accessor tasks!: Task[];
}
const project = new Project();
const task = new Task({ title: "Ship the editor" });
project.tasks.push(task); // task.parent === project, already locally
task.done = true; // MobX observers see the change
Add a shared context #
When collaboration becomes part of the application, put that existing model into a document:
const plexus = Plexus.bootstrap(project);
plexus.root === project; // The same project instance
project.tasks[0] === task; // The same task instance
task.parent === project; // The same relationship
task.uuid; // Now identifiable across environments
The document adds replicated state and cross-environment identity. A provider can now exchange that state with other clients. Your existing references and observers keep working, including when changes arrive from a peer.
This is progressive enhancement of the model: local objects are useful on their own, and document membership adds the capabilities that need a shared context. Follow the example from local to shared to watch that transition happen.
Useful locally, ready to share #
Move objects with their identity
Add parent-child relationships where your model needs ownership. Moving a block between groups updates both sides, and references still point to it. This works locally too.
Ownership and references →React to local and remote edits
Observe your local model with MobX. The same observers keep working when the model joins a document and receives changes from other clients.
Reactivity and transactions →Gain identity across environments
Locally, an object is its own identity. Joining a document adds a UUID so other environments can refer to that same entity.
Local and shared identity →Where Plexus fits #
Your UI reads and writes Plexus models, and MobX tracks the fields it reads. When those models join a document, Yjs carries their replicated state. A provider exchanges updates between clients.
| Responsibility | Handled by |
|---|---|
| Models, ownership, references, document identity | Plexus |
| Replicated document updates | Yjs |
| Reactive reads and derived values | MobX, integrated by Plexus |
| Network connection and reconnection | Your Yjs provider |
| Persistence, authentication, authorization | Your application and server |
Use your existing Yjs infrastructure, or explore plexus-do for a Cloudflare Durable Object sync server. Connecting clients explains who creates the document and when a client can join.
Try it on a real application #
Drawing editor
Excalidraw
Frames own shapes, arrows reference their endpoints, and the editor keeps its existing React surface. Edit a scene and watch a second client.
Explore the Excalidraw example →Graph editor
React Flow
Move nodes between groups while edges keep their endpoints. Inspect how ownership and references map onto a graph.
Explore the React Flow example →Why Plexus exists #
The usual CRDT tutorial works. A TodoMVC-grade app also works. Then a real application introduces related objects, document boundaries, providers, and persistence. Something does not sync, nothing throws, and days disappear.
A Carnegie Mellon user study examined the difficulties JavaScript developers encounter with collaborative data libraries. The discussion under a widely-read Yjs tutorial points to the same gap between a working demo and an application with a substantial data model.
Plexus lets a model grow from local use into collaboration. Classes, collections, relationships, and reactive reads already work in a local application. Joining a document enriches those same objects with replicated state and shared identity. Operations that violate ownership or document invariants throw explicit errors, keeping the model understandable as its context grows.