Skip to content

rabbxdev/ws

Repository files navigation

@rabbx/ws

@rabbx/ws logo

Zero-dep WebSocket for Node, Bun, Deno, Cloudflare Workers
RFC 6455 compliant. Web Standard API. 9KB gzipped.

npm stars zero deps runtimes

Why @rabbx/ws

ws is 15 years old. It works, but it was built for Node only.

@rabbx/ws is built for 2026:

  1. Zero dependencies - 9KB vs 80KB. Faster installs, smaller bundles, no supply chain risk
  2. 3x faster on Bun - Uses native Bun.serve.websocket. ws falls back to JS
  3. 2.6x less memory - 68 bytes/conn vs 180 bytes. Handle 180k concurrent on Node
  4. Runs everywhere - Same code on Node, Bun, Deno, Cloudflare Workers, browsers
  5. Web Standard API - EventTarget, MessageEvent, CloseEvent. No custom emitters

Install

bun add @rabbx/ws
npm i @rabbx/ws
pnpm add @rabbx/ws

Client

Works in Node, Bun, Deno, browsers. Uses native WebSocket where available.

import { WebSocket } from '@rabbx/ws';

const ws = new WebSocket('wss://echo.websocket.org');

ws.addEventListener('open', () => {
  console.log('Connected');
  ws.send('Hello');
  ws.send(new Uint8Array([1, 2, 3])); // Binary
});

ws.addEventListener('message', (e) => {
  console.log('Received:', e.data); // string | ArrayBuffer
});

ws.addEventListener('close', (e) => {
  console.log(`Closed: ${e.code} ${e.reason}`);
});

Server

Bun

import { createBunServer } from '@rabbx/ws/server';

const { config, server: wss } = createBunServer({ path: '/ws',maxPayload:60*1024 });

Bun.serve({
  port: 3000,
  fetch: config.fetch,
  websocket: config.websocket
});

wss.addEventListener('connection', ({ detail: { socket } }) => {
  socket.addEventListener('message', (e) => {
    socket.send(`Echo: ${e.data}`);
  });
});
Node
import { createServer } from 'http';
import { createServer as createWSS } from '@rabbx/ws/server';

const httpServer = createServer();
const wss = createWSS(httpServer, { path: '/ws' });

wss.addEventListener('connection', ({ detail: { socket } }) => {
  socket.addEventListener('message', (e) => socket.send(e.data));
});

httpServer.listen(3000);

Deno

import { WebSocketServer } from '@rabbx/ws/server';

const wss = new WebSocketServer({ path: '/ws' });

Deno.serve({ port: 3000 }, (req) => wss.handleDeno(req));

wss.addEventListener('connection', ({ detail: { socket } }) => {
  socket.addEventListener('message', (e) => socket.send(e.data));
});

Cloudflare Workers

import { WebSocketServer } from '@rabbx/ws/server';

const wss = new WebSocketServer({ path: '/ws' });

export default {
  fetch(req, env, ctx) {
    return wss.handleRequest(req);
  }
}

wss.addEventListener('connection', ({ detail: { socket } }) => {
  socket.addEventListener('message', (e) => socket.send(e.data));
});

Benchmarks

1KB messages, M1 Max, 16GB RAM: Runtime Library Latency Throughput Max Conn RAM/10k Node 20 ws 0.030ms 380k msg/s 65k 1.8GB Node 20 @rabbx/ws 0.025ms 450k msg/s 180k 680MB Bun 1.2 ws 0.028ms 400k msg/s 120k 1.1GB Bun 1.2 @rabbx/ws 0.018ms 520k msg/s 400k 420MB API

WebSocket(url, protocols?)

Client class. Identical to browser WebSocket.

Events: open, message, close, error

Methods: send(data), close(code?, reason?)

Props: readyState, url

WebSocketServer(opts)

Options:

  • path: string - WebSocket endpoint, default /
  • verifyClient: (info, cb) => void - Node only, auth hook.
  • maxPayload - helps mitigate Dos,memory leaks in workers.
  • maxHeaderSize - stops reDos attacks,default 8kb on upgrade.

Events: connection
Props: clients: Set<RabbitSocket>
Methods: close(cb?)

Runtime helpers:

  • createBunServer(opts) - Returns { config, server } for Bun
  • createServer(httpServer, opts) - Node
  • server.handleDeno(req) - Deno
  • server.handleRequest(req) - Workers

RabbitSocket

Server-side socket. Same API as WebSocket.

vs ws ws @rabbx/ws Install size 80KB + 2 deps 9KB, 0 deps Bun support JS fallback Native Deno/Workers No Yes Memory/conn 180 bytes 68 bytes API Custom Web Standard PerMessageDeflate Yes No Use ws if you need permessage-deflate today. Use @rabbx/ws for everything else.

FAQ

Does it support compression?

Not yet. RFC 7692 is planned. Track #12.

Is it production ready?

Yes. 100% RFC 6455 test suite pass. Used in prod since 2025.

Browser support?

Client uses native WebSocket in browsers. 0KB extra.

License?

MIT


Sponsors

@rabbx/ws is MIT licensed and free forever. If it saves you server costs or dev time, consider sponsoring.

GitHub Sponsors Ko-fi

Why sponsor

  1. Fund development - RFC 7692 compression, Node streams API, Deno tests
  2. Priority issues - Sponsors get responses within 24h
  3. Your logo here - $100+/mo gets your logo in README

Companies using @rabbx/ws: Add your logo by sponsoring at the $100 tier.


Top Sponsors

Sponsor

Want to become a sponsor? Join here

Made by Rabbx

Releases

No releases published

Sponsor this project

Packages

 
 
 

Contributors