LiveText: a new data type for collaborative text editing
Introducing LiveText, a new primitive for adding realtime multiplayer to rich-text editors. An alternative to Yjs, it supports Tiptap, BlockNote, ProseMirror, and CodeMirror.
Today, we’re introducing LiveText, a new data type for Liveblocks
Sync, that enables collaborative text editing, without Yjs. It currently
supports four popular rich-text and code editors,
and has a number of advantages over alternative solutions, including its
simplicity and smaller document size.
Text documents are central to how people work together, being used for project
briefs, notes, planning, and more. Traditionally, when two people edit a text
document at the same time, whoever presses save last will overwrite the other’s
changes. With collaborative text editing, multiple users can edit a document in
realtime, and their changes are merged together, without losing any data.
A block-based editor in our Next.js Starter Kit, powered by BlockNote and LiveText.
Setting up collaborative text editing is already simple with Yjs, but
this solution has always had flaws. That’s why
we’ve built a new and improved alternative, LiveText.
Our sync engine for building collaborative applications, Liveblocks Sync,
now has native support for multiplayer text editing with LiveText. It’s
quicker, simpler, and more efficient than Yjs, and shares the same undo/redo
stack as the rest of your Liveblocks app.
LiveText ships with integrations for four different editors. Each has its
own unique features and use cases, but all support collaborative text editing:
Tiptap: A headless rich-text
editor framework built on ProseMirror.
BlockNote: A block-based
rich-text editor for Notion-style documents.
ProseMirror: A toolkit for
building custom rich-text editors.
CodeMirror: An extensible code
editor for the browser.
Each link above takes you to the API reference for the editor’s integration
package.
Each editor integration supports multiple documents per room, allowing you to
render them all on the same page. To do this, for example with Tiptap, you pass
a field property as a unique identifier for the document.
You don’t need to use a specific editor to use LiveText, even though that
is the easiest way to get started. Because it’s a conflict-free data type like
LiveObject,
LiveList, and
LiveMap, you can add it to
your data storage tree and read/edit it like any other data.
You can define a new value with the
LiveText constructor. In
this example, a multiplayer room is initialized, and the myText property is
defined with a default value of “Hello”.
Formatting can be applied to each segment of the text when modifying it, using
format. In this
example, the text is transformed from “Hello world” to “Hello world”.
LiveText can be deeply nested inside other data types, such as
LiveObject, LiveList, and LiveMap. This allows you to create
complex, dynamic data trees that multiple users can edit in realtime. In this
example, an app has a LiveList of pages, and each page’s LiveText
content is stored inside a LiveObject.
As existing apps become
places where humans and agents work together,
it was important for us to enable agentic editing of text. Using existing APIs
for Liveblocks Sync, you can create AI agents that can edit LiveText
content from the back end. This is possible using
mutateStorage, which
works similarly to useMutation.
import{ Liveblocks }from"@liveblocks/node";import{ openai }from"@ai-sdk/openai";import{ generateText }from"ai"; const liveblocks =newLiveblocks({ secret:"sk_prod_xxxxxxxxxxxxxxxxxxxxxxxx",}); const{ text }=awaitgenerateText({ model:openai("gpt-5.6-sol"), prompt:`Write a document about realtime collaboration`,}); await liveblocks.mutateStorage("my-room-id",({ root })=>{const myText = root.get("myText"); myText.insert(0, text);});
An alternative method for editing text on the server is to use
JSON Patch. This is a standard format for describing
changes to a JSON document, and LiveText supports it. For example, the
snippet below replaces the first segment of the text with “Hello”, and then
makes it bold.
Until now, text editing in Liveblocks has been powered by Yjs, a CRDT
library.
CRDTs are
designed so that every client can merge every edit independently, without a
central server. It’s clever technology, but that independence has a cost;
because to merge correctly, a CRDT document must remember its past.
Deleted content leaves behind tombstones, hidden markers that stay in the
document forever, so a Yjs document grows with every edit, even deletions. A
document that’s edited daily gets steadily larger, and slower to load, for its
entire life. And on top of that, because CRDT state is stored as binary deltas,
reading or editing a document outside the editor means decoding that format
first, which adds extra complexity.
Liveblocks doesn’t have this constraint. Because our server is authoritative, it
can put every edit in order and resolve conflicts centrally using
operational transformation
instead of a CRDT. The document only ever needs to store its current contents,
without any tombstones or accumulated history.
In practice, this means:
Documents never grow over time. A document edited daily for years is the
same size as one written yesterday, and loads just as fast.
No binary deltas. Your text is plain, readable data. Inspect it in the
dashboard, fetch it with the
REST API, react to changes with
webhooks.
One engine for everything. Text, presence, and structured data are
conflict-resolved by a single sync engine, using the same permissions and
undo/redo history.
There’s one trade-off to be aware of, which is that each LiveText has a
maximum size of 2 MB. A room can hold any number of them, and 2 MB is
plenty for typical documents, such as notes, briefs, page content, and text
fields. However, it does mean that Yjs is a better fit for very large,
book-length documents. We’ll be exploring expanding the maximum size in future.
If you’re using Liveblocks and Yjs today, nothing changes! We’re not dropping
support for Yjs, and there’s no need to migrate. You can continue using Yjs with
Liveblocks, and it will keep working as expected. However, for most new
projects, we recommend using LiveText instead, as it’s a better experience
for collaborative text editing.