WebSockets

Server-side WebSockets in Bun

Bun.serve() supports server-side WebSockets, with on-the-fly compression, TLS support, and a Bun-native publish-subscribe API.

⚡️ 7x more throughput

Bun's WebSockets are fast. For a simple chatroom on Linux x64, Bun can handle 7x more messages per second than Node.js + "ws".

Messages sent per secondRuntimeClients
~700,000(Bun.serve) Bun v0.2.1 (x64)16
~100,000(ws) Node v18.10.0 (x64)16

Internally Bun's WebSocket implementation is built on uWebSockets.


Start a WebSocket server#

The following server, built with Bun.serve, upgrades every incoming request to a WebSocket connection in the fetch handler. You declare the socket handlers in the websocket parameter.

server.ts
Bun.serve({
  fetch(req, server) {
    // upgrade the request to a WebSocket
    if (server.upgrade(req)) {
      return; // do not return a Response
    }
    return new Response("Upgrade failed", { status: 500 });
  },
  websocket: {}, // handlers
});

Bun supports these WebSocket event handlers:

server.ts
Bun.serve({
  fetch(req, server) {}, // upgrade logic
  websocket: {
    message(ws, message) {}, // a message is received
    open(ws) {}, // a socket is opened
    close(ws, code, message) {}, // a socket is closed
    drain(ws) {}, // the socket is ready to receive more data
  },
});
An API designed for speed

In Bun, you declare handlers once per server, instead of per socket.

You pass a single WebSocketHandler object to Bun.serve() with methods for open, message, close, drain, and error. This design differs from the client-side WebSocket class, which extends EventTarget (onmessage, onopen, onclose).

Clients tend to have few socket connections open, so an event-based API makes sense there.

But servers tend to have many socket connections open, which means:

  • Time spent adding/removing event listeners for each connection adds up
  • Extra memory spent on storing references to callback functions for each connection
  • Usually, people create new functions for each connection, which also means more memory

Reusing one handler object across every connection avoids both costs.

The first argument to each handler is the ServerWebSocket instance handling the event. The ServerWebSocket class is a fast, Bun-native implementation of WebSocket with some additional features.

server.ts
Bun.serve