Skip to content
Meeko
Type to search the guides and the API reference. Open it from any page with / or Ctrl K; move with the arrow keys and open a result with Enter.
Get started

Contents

On this page

DurableObjectSocketPubSub

The Socket broker for Cloudflare Workers, where each channel and room is a Durable Object that receives publications over RPC and distributes them to its peers.

adapter Since 1.0.0 @meekojs/meeko/cloudflare Source code
ts
import { DurableObjectSocketPubSub } from "@meekojs/meeko/cloudflare";

On Workers, Socket connections do not live in the isolate handling the request, but in their room's Durable Object. DurableObjectSocketPubSub is the only broker that reaches them: publish delivers the message to the room over RPC (or directly, if already running inside that room) and resolves when the room accepts it; the room distributes it to its peers in publication order.

It is the default broker on Workers: with the MEEKO_SOCKET binding and no socket.pubsub, the generated Worker uses it. Declare it only to make it explicit or use another binding; any other broker is rejected.

Usage#

ts
// server/runtime.ts
import { DurableObjectSocketPubSub } from "@meekojs/meeko/cloudflare";
import type { DurableObjectNamespaceLike } from "@meekojs/meeko/cloudflare";
import { defineServerRuntime } from "@meekojs/meeko/server";

interface Env { readonly MEEKO_SOCKET?: DurableObjectNamespaceLike }

export default defineServerRuntime<Env>(({ env }) => ({
  socket: env.MEEKO_SOCKET ? { pubsub: new DurableObjectSocketPubSub(env.MEEKO_SOCKET) } : {},
}));

env.MEEKO_SOCKET does not exist during prerendering, which runs in Node.

Type#

ts
class DurableObjectSocketPubSub implements SocketPubSub {
  constructor(namespace: DurableObjectNamespaceLike);
  publish(channel: string, room: string, message: SocketMessage): Promise<void>;
  subscribe(channel: string, room: string, listener: RoomListener): Unsubscribe;
}

DurableObjectNamespaceLike

ts
interface DurableObjectNamespaceLike {
	idFromName(name: string): DurableObjectIdLike
	get(id: DurableObjectIdLike): DurableObjectStubLike
}

SocketPubSub

ts
interface SocketPubSub {
  publish(channel: string, room: string, message: SocketMessage): Promise<void>;
  subscribe(
    channel: string,
    room: string,
    listener: (message: SocketMessage) => void | Promise<void>,
  ): Unsubscribe | Promise<Unsubscribe>;
}

Parameters#

new DurableObjectSocketPubSub(namespace):

Parameter Type Description
namespace DurableObjectNamespaceLike The room namespace binding, usually env.MEEKO_SOCKET, whose class was created with createSocketRoomClass.

Return value#

A SocketPubSub:

Method Description
publish(channel, room, message) Delivers the message to the Durable Object for socketRoomName(channel, room) and resolves when it accepts it. Rejects with SOCKET_BACKLOG_EXCEEDED (503) if the room already has maxPendingPublications undelivered publications.
subscribe(channel, room, listener) Only inside the room's Durable Object, where the hub subscribes its peers.

Examples#

Broadcasting from an API#

ts
// server/api/documents/[id]/publish.post.ts
export default defineApiRoute({
  params: documentParams,
  response: documentSchema,
  auth: "required",
  handler: async ({ params }) => {
    const document = await publishDocument(params.id);
    await socket.documents.broadcast(document.id, "published", { id: document.id, at: document.publishedAt });
    return document;
  },
});

The same code works on Node with LocalSocketPubSub or RedisSocketPubSub: broadcast uses the runtime's broker.

One room per document#

texto
/_meeko/socket/documents?room=doc_42  → Durable Object "documents\u0000doc_42"
/_meeko/socket/documents?room=doc_43  → Durable Object "documents\u0000doc_43"

Each room processes its messages on a single thread: dividing rooms by document scales better than a global room.

Common mistakes#

A binding that is not for Durable Objects#

Incorrectts
new DurableObjectSocketPubSub(env.DB as never);

TypeError: DurableObjectSocketPubSub requires a Durable Object namespace binding.

Correctts
new DurableObjectSocketPubSub(env.MEEKO_SOCKET);

Subscribing outside the room#

Incorrectts
new DurableObjectSocketPubSub(env.MEEKO_SOCKET).subscribe("chat", "general", (message) => console.log(message));

Error: DurableObjectSocketPubSub subscribes only inside the Socket room Durable Object; forward upgrades with createWorker. Subscriptions exist only inside the room; every upgrade must go through createWorker.

Correctts
export default createWorker(createCloudflareApp); // forwards each upgrade to its room

A room class that is not Meeko's#

Incorrecttexto
MEEKO_SOCKET points to a custom Durable Object class

The first publish rejects with TypeError: The Socket Durable Object must be created with createSocketRoomClass: the room must expose the meekoPublish RPC.

Correcttexto
export const MeekoSocketRoom = createSocketRoomClass(createCloudflareApp, DurableObject);

Another broker on Workers#

Incorrectts
socket: { pubsub: new LocalSocketPubSub() }

The Worker and room reject the application on creation: Socket channels on Cloudflare Workers require DurableObjectSocketPubSub: leave runtime.socket.pubsub unset and bind MEEKO_SOCKET, or set it to new DurableObjectSocketPubSub(env.MEEKO_SOCKET)….

Correctts
socket: {} // the Worker uses DurableObjectSocketPubSub(env.MEEKO_SOCKET)

Notes#

  • Delivery. At most once, in publication order per room. A publication to the same room does not use RPC.
  • Validation. The hub validates the event and payload before publishing; the room validates them again and applies authorize and authorizeSend to each peer.
  • Hibernation. A publication wakes the room if it was hibernating; it waits at most rebuildTimeoutMs for connections to be reconstructed.
  • No TCP or Redis. No external broker is needed: the Durable Object is each room's single coordination point.

Was this page helpful?

Add a comment

It is sent when you choose “Yes” or “No”. Only the page, your answer and the comment are stored: no cookies and no personal data.

0 of 2000 characters

Edit on GitHub: docs/en/reference/adapters/durableobjectsocketpubsub.md