WebSockets

H3 has built-in utilities for cross platform WebSocket and Server-Sent Events.

You can add cross platform WebSocket support to H3 servers using 🔌 CrossWS.

Built-in support of WebSockets in h3 version is WIP.

Usage

WebSocket handlers can be defined using the defineWebSocketHandler() utility and registered to any route like event handlers.

You need to register CrossWS as a server plugin in the serve function and provide a resolve function to resolve the correct hooks from the route.

import { H3, serve, defineWebSocketHandler } from "h3";

import { plugin as ws } from "crossws/server";

const app = new H3()

app.get("/_ws", defineWebSocketHandler({ message: console.log }));

serve(app, {
  plugins: [ws({ resolve: async (req) => (await app.fetch(req)).crossws })],
});

Full example:

websocket.mjs
import { H3, serve, defineWebSocketHandler } from "h3";
import { plugin as ws } from "crossws/server";

export const app = new H3();

const demoURL =
  "https://raw.githubusercontent.com/h3js/crossws/refs/heads/main/playground/public/index.html";

app.get("/", () =>
  fetch(demoURL).then(
    (res) =>
      new Response(res.body, { headers: { "Content-Type": "text/html" } }),
  ),
);

app.get(
  "/_ws",
  defineWebSocketHandler({
    // upgrade(req) {},
    open(peer) {
      console.log("[open]", peer);

      // Send welcome to the new client
      peer.send("Welcome to the server!");

      // Join new client to the "chat" channel
      peer.subscribe("chat");

      // Notify every other connected client
      peer.publish("chat", `[system] ${peer} joined!`);
    },

    message(peer, message) {
      console.log("[message]", peer);

      if (message.text() === "ping") {
        // Reply to the client with a ping response
        peer.send("pong");
        return;
      }

      // The server re-broadcasts incoming messages to everyone
      peer.publish("chat", `[${peer}] ${message}`);

      // Echo the message back to the sender
      peer.send(message);
    },

    close(peer) {
      console.log("[close]", peer);
      peer.publish("chat", `[system] ${peer} has left the chat!`);
      peer.unsubscribe("chat");
    },
  }),
);

serve(app, {
  plugins: [ws({ resolve: async (req) => (await app.fetch(req)).crossws })],
});

Server-Sent Events (SSE)

As an alternative to WebSockets, you can use Server-sent events.

H3 has a built-in API to create server-sent events using createEventStream(event) utility.

Example

server-sent-events.mjs
import { H3, serve, createEventStream } from "h3";

export const app = new H3();

app.get("/", (event) => {
  const eventStream = createEventStream(event);

  // Send a message every second
  const interval = setInterval(async () => {
    await eventStream.push("Hello world");
  }, 1000);

  // cleanup the interval when the connection is terminated or the writer is closed
  eventStream.onClosed(() => {
    console.log("Connection closed");
    clearInterval(interval);
  });

  return eventStream.send();
});

serve(app);