yjs-getting-started

star 1.6k

First-time setup for @durable-streams/y-durable-streams. Install peer deps, start dev servers (DurableStreamTestServer + YjsServer), create a collaborative Y.Doc, connect with YjsProvider, verify sync, add awareness for presence. Load when setting up Yjs collaborative editing for the first time.

durable-streams By durable-streams schedule Updated 4/13/2026

name: yjs-getting-started description: > First-time setup for @durable-streams/y-durable-streams. Install peer deps, start dev servers (DurableStreamTestServer + YjsServer), create a collaborative Y.Doc, connect with YjsProvider, verify sync, add awareness for presence. Load when setting up Yjs collaborative editing for the first time. type: lifecycle library: durable-streams library_version: "0.2.3" sources: - "durable-streams/durable-streams:packages/y-durable-streams/src/yjs-provider.ts" - "durable-streams/durable-streams:packages/y-durable-streams/src/server/yjs-server.ts" - "durable-streams/durable-streams:packages/y-durable-streams/README.md"

Durable Streams — Yjs Getting Started

Sync Yjs documents over HTTP durable streams. No WebSocket infrastructure needed — uses standard HTTP with SSE or long-poll transport.

Install

npm install @durable-streams/y-durable-streams yjs y-protocols lib0

yjs, y-protocols, and lib0 are peer dependencies — missing them causes runtime import errors.

For the dev server (not needed if using Electric Cloud):

npm install -D @durable-streams/server

Start dev servers

Two servers are needed: a Durable Streams storage server and a Yjs protocol server that sits in front of it.

import { DurableStreamTestServer } from "@durable-streams/server"
import { YjsServer } from "@durable-streams/y-durable-streams/server"

// 1. Storage server
const dsServer = new DurableStreamTestServer({ port: 4437 })
await dsServer.start()

// 2. Yjs protocol server (proxies to storage server)
const yjsServer = new YjsServer({
  port: 4438,
  dsServerUrl: `http://localhost:4437`,
})
await yjsServer.start()

console.log(`Yjs server ready at http://localhost:4438`)

Create a collaborative document

import { YjsProvider } from "@durable-streams/y-durable-streams"
import * as Y from "yjs"

const doc = new Y.Doc()

const provider = new YjsProvider({
  doc,
  baseUrl: "http://localhost:4438/v1/yjs/my-service",
  docId: "my-doc",
})

provider.on("synced", (synced) => {
  if (synced) {
    console.log("Document synced with server")
    // Edit the document — changes sync automatically
    doc.getText("content").insert(0, "Hello from Yjs!")
  }
})

baseUrl is the service root. The provider builds URLs as {baseUrl}/docs/{docId} internally — do not include /docs/ in baseUrl.

Add presence

import { Awareness } from "y-protocols/awareness"

const awareness = new Awareness(doc)
awareness.setLocalStateField("user", {
  name: "Alice",
  color: "#ff0000",
})

const provider = new YjsProvider({
  doc,
  baseUrl: "http://localhost:4438/v1/yjs/my-service",
  docId: "my-doc",
  awareness,
})

// Listen for remote users
awareness.on("change", () => {
  const users = Array.from(awareness.getStates().values())
    .filter((s) => s?.user)
    .map((s) => s.user.name)
  console.log("Online:", users)
})

Use setLocalStateField("user", ...) (merges) not setLocalState(...) (replaces). setLocalState overwrites all awareness fields, breaking cursor tracking or other awareness data set by editor bindings.

Common Mistakes

CRITICAL Missing peer dependencies

Wrong:

npm install @durable-streams/y-durable-streams

Correct:

npm install @durable-streams/y-durable-streams yjs y-protocols lib0

Source: packages/y-durable-streams/package.json peerDependencies

HIGH Including /docs/ in baseUrl

Wrong:

new YjsProvider({
  doc,
  baseUrl: "http://localhost:4438/v1/yjs/my-service/docs/my-doc",
  docId: "my-doc",
})

Correct:

new YjsProvider({
  doc,
  baseUrl: "http://localhost:4438/v1/yjs/my-service",
  docId: "my-doc",
})

The provider appends /docs/{docId} internally. Doubling /docs/ produces 404s.

Source: packages/y-durable-streams/src/yjs-provider.ts docUrl()

HIGH Starting YjsServer without a backing DS server

// This will fail — YjsServer needs a running DS server
const yjsServer = new YjsServer({
  port: 4438,
  dsServerUrl: "http://localhost:4437", // Must be running first
})

YjsServer proxies all storage operations to the DS server. Start DurableStreamTestServer (or Caddy) before starting YjsServer.

See also

  • yjs-editors — TipTap and CodeMirror integration
  • yjs-sync — Provider lifecycle, events, error recovery
  • yjs-server — Production deployment with Caddy or Electric Cloud
Install via CLI
npx skills add https://github.com/durable-streams/durable-streams --skill yjs-getting-started
Repository Details
star Stars 1,571
call_split Forks 59
navigation Branch main
article Path SKILL.md
More from Creator
durable-streams
durable-streams Explore all skills →