is in preview! Please wait for a v1.0.0 stable release before using this in production.

Node.js supports building real-time APIs with Node.js. You can define your handler and websocket server manually if you need more control, but if you'd like to get started quicky, check out createPluvHandler.

Using with Node.js (manual)

Let's step through how we'd put together a real-time API for Node.js.

Install dependencies

# For the server
npm install @pluv/io @pluv/platform-node

# Server peer-dependencies
npm install ws zod

Create PluvIO instance

Define an io (websocket client) instance on the server codebase:

// backend/io.ts

import { createIO } from "@pluv/io";
import { platformNode } from "@pluv/platform-node";

export const io = createIO({ platform: platformNode() });

export const ioServer = io.server();

// Export the ioServer type, so that this can be type-imported on the frontend
export type AppPluvIO = typeof ioServer;

Integrate PluvIO with ws

Integrate with ws on your Node.js server.

// backend/server.ts

import express from "express";
import Http from "http";
import WebSocket from "ws";
import { ioServer } from "./io";

const PORT = 3000;

const app = express();
const server = Http.createServer();
const wsServer = new WebSocket.Server({ server });

const parseRoomId = (url: string): string => {
    /* get room from req.url */

wsServer.on("connection", async (ws, req) => {
    const roomId = parseRoomId(req.url);
    const room = ioServer.getRoom(roomId);

    await room.register(ws);

server.listen(PORT, () => {
    console.log(`Server is listening on port: ${port}`);


If you don't need to modify your websocket server or handler too specifically, @pluv/platform-node also provides a function createPluvHandler to create a websocket server and handler for your automatically.

import { createIO } from "@pluv/io";
import { createPluvHandler, platformNode } from "@pluv/platform-node";
import bodyParser from "body-parser";
import cors from "cors";
import express from "express";
import Http from "http";
import WS from "ws";

const io = createIO({ platform: platformNode() });
const ioServer = io.server();

const app = express();
const server = Http.createServer(app);

const Pluv = createPluvHandler({
    // Your PluvServer instance
    io: ioServer,
    // Optional: Specify the base path from which endpoints are defined
    endpoint: "/api/pluv", // defaults to "/api/pluv"
    // Your Http.Server instance
    // If your PluvIO instance defines authorization, add your authorization
    // logic here. Return a user if authorized, return null or throw an error
    // if not authorized.
    async authorize({ req, res, roomId }) {
        return {
            id: "abc123",
            name: "leedavidcs",

// Create your WS.Server instance, which listens to "connection" events
const wsServer = Pluv.createWsServer();

// Alternatively, define your own websocket server
const wsServer = new WS.Server({ server });

wsServer.on("connection", async (ws, req) => {
    const { matched } = await Pluv.wsHandler(ws, req);

    if (matched) return;

    // didn't match with the Pluv handler, add your own logic
    // ...

app.use(cors({ origin: "*" }));