Yjs PostgreSQL Persistence

1.0.1 · active · verified Wed Apr 22

y-postgresql is a community-maintained PostgreSQL database adapter designed to provide persistent storage for Yjs documents, commonly used in conjunction with a `y-websocket` server for real-time collaborative applications. As of version `1.0.1`, it offers features for storing Yjs updates and retrieving full document states from PostgreSQL. The package differentiates itself by providing a robust, battle-tested persistence solution for PostgreSQL users within the Yjs ecosystem, handling the serialization and deserialization of Yjs document updates directly. While it is not officially supported by the Yjs core team, it maintains compatibility with recent Yjs versions and provides configurable options like table naming, flush size for merging updates, and indexing for performance tuning. Release cadence is independent of Yjs core, typically driven by community contributions and specific feature requirements or bug fixes related to PostgreSQL integration.

Common errors

Warnings

Install

Imports

Quickstart

This example sets up a basic `y-websocket` server and integrates `y-postgresql` for persistent storage of Yjs documents in a PostgreSQL database, demonstrating connection, state binding, and update storage.

import 'dotenv/config';
import http from 'http';
import { WebSocketServer } from 'ws';
import * as Y from 'yjs';
// Assuming these utilities are available from y-websocket or a local setup
import { setPersistence, setupWSConnection } from './websocket/utils.js'; 
import { PostgresqlPersistence } from 'y-postgresql';

const server = http.createServer((request, response) => {
	response.writeHead(200, { 'Content-Type': 'text/plain' });
	response.end('okay');
});

const wss = new WebSocketServer({ server });
wss.on('connection', setupWSConnection); // Use the y-websocket setup utility

async function startPersistence() {
    const pgdb = await PostgresqlPersistence.build(
        {
            host: process.env.PG_HOST ?? 'localhost',
            port: parseInt(process.env.PG_PORT ?? '5432', 10),
            database: process.env.PG_DATABASE ?? 'yjs_db',
            user: process.env.PG_USER ?? 'postgres',
            password: process.env.PG_PASSWORD ?? '',
        },
        { tableName: 'yjs-documents', useIndex: true, flushSize: 200 },
    );

    setPersistence({
        bindState: async (docName, ydoc) => {
            const persistedYdoc = await pgdb.getYDoc(docName);
            Y.applyUpdate(ydoc, Y.encodeStateAsUpdate(persistedYdoc));
            ydoc.on('update', async (update: Uint8Array) => {
                pgdb.storeUpdate(docName, update);
            });
        },
        writeState: async (docName, ydoc) => {
            // Optional: Ensure all updates are flushed before document destroy
            return new Promise((resolve) => resolve());
        },
    });
    
    server.listen(process.env.PORT ?? 8080, () => {
        console.log(`y-websocket server with y-postgresql persistence listening on port: ${process.env.PORT ?? 8080}`);
    });
}

startPersistence().catch(console.error);

view raw JSON →