MongoDB Persistence Provider for Yjs
y-mongodb-provider is a database adapter that enables persistent storage and retrieval of Yjs collaborative documents using MongoDB. It serves as a backend for y-websocket servers, allowing Yjs document states to be saved and loaded, thereby ensuring data durability across server restarts or disconnections. The current stable version is 0.2.1, with updates primarily focused on dependency management, internal driver improvements, and bug fixes, indicating an active development status though without a strict release cadence. Key differentiators include its specific integration with MongoDB (unlike Yjs's officially supported y-leveldb), its ability to handle Yjs updates exceeding MongoDB's 16MB document size limit (since v0.1.8), and its use of the official MongoDB Node.js Driver for enhanced security and performance. It's important to note that this package is not officially supported by the Yjs team.
Warnings
- gotcha This `y-mongodb-provider` package is not officially supported or maintained by the core Yjs team. While functional, users should be aware of its community-driven support model.
- breaking Node.js version 16 or newer is required to use this package. Using older Node.js versions will result in runtime errors due to reliance on modern JavaScript features and ESM module format.
- breaking Version 0.1.8 replaced the internal 'mongoist' library with the official 'mongodb' Node.js Driver. While the public API signature for `MongodbPersistence` generally remained, internal behaviors, error handling, or specific connection options might have changed. This change was also made for security enhancements.
- gotcha For optimal performance and robust connection pooling, especially when sharing a `MongoClient` instance across your application, it is recommended to pass an object `{ client: MongoClient, db: Db }` to the `MongodbPersistence` constructor instead of just a connection string. This avoids creating redundant MongoDB client instances.
- gotcha If the `multipleCollections` option is set to `true` in the `MongodbPersistence` constructor, each Yjs document will be stored in its own dedicated MongoDB collection. In this scenario, the `collectionName` option will be ignored.
- breaking Version 0.2.0 introduced changes to the `MongodbPersistence` constructor's internal handling of the database name for user authentication. While passing a connection string is still supported, improper database naming could lead to authentication failures or incorrect access rights.
Install
-
npm install y-mongodb-provider -
yarn add y-mongodb-provider -
pnpm add y-mongodb-provider
Imports
- MongodbPersistence
const { MongodbPersistence } = require('y-mongodb-provider')import { MongodbPersistence } from 'y-mongodb-provider' - MongodbPersistence constructor (connection string)
new MongodbPersistence('mongodb://localhost:27017/yjstest') - MongodbPersistence constructor (client object)
import { MongoClient } from 'mongodb'; const client = new MongoClient('mongodb://localhost:27017'); await client.connect(); const db = client.db('yourDatabaseName'); new MongodbPersistence({ client, db })
Quickstart
import http from 'http';
import { WebSocketServer } from 'ws';
import * as Y from 'yjs';
import { MongodbPersistence } from 'y-mongodb-provider';
import yUtils from 'y-websocket/bin/utils'; // Note: y-websocket/bin/utils is an internal utility, adapt as needed.
const port = process.env.PORT || 1234;
const mongoConnectionString = process.env.MONGODB_URL || 'mongodb://localhost:27017/yjstest';
const server = http.createServer((request, response) => {
response.writeHead(200, { 'Content-Type': 'text/plain' });
response.end('okay');
});
// Initialize Yjs WebSocket server
const wss = new WebSocketServer({ server });
wss.on('connection', yUtils.setupWSConnection);
// Initialize MongoDB persistence for Yjs
const mdb = new MongodbPersistence(mongoConnectionString, {
collectionName: 'transactions',
flushSize: 100,
multipleCollections: false, // Default; set to true if each document needs its own collection
});
// Set up persistence with y-websocket
yUtils.setPersistence({
bindState: async (docName, ydoc) => {
// Retrieve the persisted document state
const persistedYdoc = await mdb.getYDoc(docName);
// Apply the persisted state to the current ydoc
Y.applyUpdate(ydoc, Y.encodeStateAsUpdate(persistedYdoc));
// Store initial state and listen for future updates
mdb.storeUpdate(docName, Y.encodeStateAsUpdate(ydoc));
ydoc.on('update', async (update) => {
mdb.storeUpdate(docName, update);
});
},
writeState: async (docName, ydoc) => {
// This function is called when all connections to a document are closed.
// Ensure all pending updates are written to the database.
// For y-mongodb-provider, `storeUpdate` handles this incrementally.
// The promise resolution signals that the document can be destroyed.
return new Promise(resolve => resolve());
},
});
server.listen(port, () => {
console.log(`Yjs WebSocket server with MongoDB persistence listening on port: ${port}`);
});