y-monaco
Binds a Yjs shared text type to the Monaco code editor for real-time collaborative editing with shared cursors.
Repository Health
Technical Analysis
y-monaco is the official Yjs binding for the Monaco editor, the code editor that powers VS Code. It connects a Y.Text CRDT type to a Monaco text model so that edits made in any connected editor instance are merged and reflected everywhere else, without the app author having to write any conflict-resolution or transport code themselves.
Beyond plain text sync, the binding also tracks selections and cursors: local selections are converted to Yjs relative positions before a transaction so they survive concurrent remote edits, and when a y-protocols Awareness instance is supplied, other users’ cursors and selection ranges are rendered as colored Monaco decorations that update live. It ships as a single small class (MonacoBinding) with a destroy() method for clean teardown, making it easy to drop into any Yjs-powered collaborative editor alongside a provider such as y-websocket or y-webrtc.
What You Get
- A
MonacoBindingclass that keeps a YjsY.Textand one or more Monaco editor models in sync bidirectionally - Cursor and selection preservation across concurrent remote edits using Yjs relative positions
- Optional multi-user awareness rendering — remote selections and cursor heads appear as styled Monaco decorations (
yRemoteSelection,yRemoteSelectionHead) with per-client CSS hooks - A mutex-guarded update loop that prevents feedback cycles between Yjs transactions and Monaco’s own change events
- A
destroy()method that unregisters all listeners cleanly, and automatic cleanup when the Monaco model itself is disposed
Common Use Cases
- Adding Google-Docs-style real-time collaborative code editing to an in-browser IDE or notebook product
- Building pair-programming or teaching tools where multiple users edit the same file and see each other’s cursors live
- Powering the editor layer of a Yjs-based collaborative app (paired with
y-websocketory-webrtcfor transport) - Prototyping CRDT-backed multiplayer editing features on top of the same editor component used by VS Code
Under The Hood
Architecture
The binding is a single-file, single-class module (src/y-monaco.js, ~220 lines) built around one exported MonacoBinding class. It centers on a mutex (lib0/mutex) that prevents feedback loops between two independent event sources: Yjs document transactions (ytext.observe, doc.on('beforeAllTransactions', ...)) and Monaco’s own onDidChangeContent handler. Remote Yjs deltas are walked as retain/insert/delete ops and replayed into Monaco via applyEdits, converting between Yjs character indices and Monaco line/column positions with getPositionAt/getOffsetAt. Local Monaco edits are sorted right-to-left and replayed inside a single Yjs transaction so multi-range edits apply correctly against a shifting document. Selections are preserved across edits by converting them to Yjs RelativePositions before a transaction and restoring them from createAbsolutePositionFromRelativePosition afterward, and remote-user cursors from an optional Awareness instance are rendered as Monaco decorations recomputed on every awareness change event. destroy() explicitly unwinds every listener (the ytext observer, Monaco’s change/dispose handlers, and awareness), and teardown is also wired to Monaco’s own onWillDispose for automatic cleanup.
Tech Stack
monaco-editor (>=0.20.0) and yjs (^13.3.1) are peer dependencies, left to the consuming app rather than bundled; the binding itself pulls in lib0 (^0.2.43) for its mutex/error utilities and y-protocols for the Awareness type. The build uses Rollup to emit a CJS bundle (dist/y-monaco.cjs) alongside TypeScript declaration files generated via tsc from JSDoc-annotated JavaScript (checkJs: true), while a separate Webpack config drives a standalone live demo. Linting runs through standard.
Code Quality
The test suite (test/y-monaco.test.js) uses lib0/testing together with Yjs’s own randomized-testing harness (applyRandomTests from yjs/tests/testHelper.js), running many seeded random sequences of insert, delete, replace, and newline edits across two independently bound Monaco models sharing one Y.Doc, then asserting both models converge to identical content after every step — a rigorous style of test for verifying CRDT-editor binding correctness under concurrent modification. Coverage is narrower outside that path: there is no dedicated test for the awareness-decoration rendering logic, and no CI workflow configuration was found in the repository. Type safety comes from JSDoc annotations checked by the TypeScript compiler rather than native TypeScript source.
What Makes It Unique The library doesn’t introduce a new sync algorithm — it applies Yjs’s existing relative-position and delta APIs — but it gets the one genuinely tricky detail of any editor binding right: preserving each user’s cursor and selection across an edit that is being applied concurrently and out of order, by converting to relative positions before the transaction and restoring them afterward. Combined with awareness-driven remote-cursor decorations, this gives Monaco-based applications real-time multiplayer editing behavior with a single constructor call and no bespoke conflict-resolution code.
Used by 2 apps in this directory
Supabase
Developer Tools · Databases · Search
The open-source Postgres development platform that replaces Firebase with authentication, real-time APIs, edge functions, storage, and vector embeddings — all built on PostgreSQL.
Windmill
Automation · Developer Tools
Turn scripts into webhooks, workflows, and auto-generated UIs — the fastest self-hostable workflow engine, 13x faster than Airflow.