{"id":15473,"library":"partyserver","title":"PartyServer for Cloudflare Durable Objects","description":"PartyServer is a TypeScript library for building real-time applications on Cloudflare Durable Objects, inspired by PartyKit. It extends Durable Objects with features like room-based routing, lifecycle hooks (`onConnect`, `onMessage`, `onClose`), a unified API for managing hibernated and non-hibernated Durable Objects, and easy broadcasting. Key differentiators from PartyKit include decoupling the URL from the server name, omitting built-in bindings for other Cloudflare services (encouraging `wrangler`'s native support), and requiring manual Durable Object bindings and migrations in `wrangler.jsonc`. The current stable version is 0.4.1, with frequent patch and minor releases, indicating active development. It is primarily designed for the Cloudflare Workers environment and leverages WebSockets for real-time communication.","status":"active","version":"0.4.1","language":"javascript","source_language":"en","source_url":"git://github.com/cloudflare/partykit","tags":["javascript","stateful","serverless","durable objects","partykit","cloudflare","workerd","real-time","websockets","typescript"],"install":[{"cmd":"npm install partyserver","lang":"bash","label":"npm"},{"cmd":"yarn add partyserver","lang":"bash","label":"yarn"},{"cmd":"pnpm add partyserver","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Provides TypeScript type definitions for Cloudflare Workers API, essential for development.","package":"@cloudflare/workers-types","optional":false}],"imports":[{"note":"Server is a named export, not a default export. Your Durable Object class will extend this.","wrong":"import Server from 'partyserver';","symbol":"Server","correct":"import { Server } from 'partyserver';"},{"note":"Used in the Worker's `fetch` handler to delegate requests to the appropriate Durable Object based on PartyKit-style routing. `partyserver` is an ESM-first library.","wrong":"const { routePartykitRequest } = require('partyserver');","symbol":"routePartykitRequest","correct":"import { routePartykitRequest } from 'partyserver';"},{"note":"PartySocket is the recommended client library for connecting to a PartyServer instance, and is a separate package.","wrong":"import { PartySocket } from 'partyserver';","symbol":"PartySocket","correct":"import { PartySocket } from 'partysocket';"}],"quickstart":{"code":"import { routePartykitRequest, Server } from \"partyserver\";\nimport { PartySocket } from \"partysocket\";\n\ninterface Env {\n  MyServer: DurableObjectNamespace;\n}\n\n// Define your Server logic\nexport class MyServer extends Server {\n  onConnect(connection: WebSocket, context: any) {\n    console.log(`Connected ${connection.id} to server ${this.name}`);\n  }\n\n  onMessage(connection: WebSocket, message: string | ArrayBuffer) {\n    console.log(`Message from ${connection.id}:`, message);\n    // Broadcast the message to all other connections in the room\n    this.broadcast(message, [connection.id]);\n  }\n\n  onClose(connection: WebSocket, code: number, reason: string, wasClean: boolean) {\n    console.log(`Connection ${connection.id} closed. Clean: ${wasClean}`);\n  }\n}\n\n// Worker entry point to route requests to Durable Objects\nexport default {\n  async fetch(request: Request, env: Env): Promise<Response> {\n    return (\n      (await routePartykitRequest(request, env)) ||\n      new Response(\"Not Found\", { status: 404 })\n    );\n  }\n} satisfies ExportedHandler<Env>;\n\n// === Minimal wrangler.jsonc configuration ===\n/*\n{\n  \"name\": \"my-partyserver-app\",\n  \"main\": \"index.ts\",\n  \"durable_objects\": {\n    \"bindings\": [\n      {\n        \"name\": \"MyServer\",\n        \"class_name\": \"MyServer\"\n      }\n    ]\n  },\n  \"migrations\": [\n    {\n      \"tag\": \"v1\",\n      \"new_sqlite_classes\": [\"MyServer\"]\n    }\n  ]\n}\n*/\n\n// === Client-side connection example (requires 'partysocket') ===\n/*\nconst socket = new PartySocket({\n  host: \"https://my-partyserver-app.threepointone.workers.dev\",\n  party: \"my-server\", // 'my-server' corresponds to the kebab-cased Durable Object class name 'MyServer'\n  room: \"my-room\",\n  onOpen: () => console.log(\"Client connected!\"),\n  onMessage: (event) => console.log(\"Client received message:\", event.data),\n  onClose: () => console.log(\"Client disconnected\"),\n  onError: (event) => console.error(\"Client error:\", event)\n});\n\n// To send a message from the client\n// socket.send(\"Hello from client!\");\n*/\n","lang":"typescript","description":"Demonstrates a basic PartyServer setup with a Durable Object and its lifecycle hooks, along with the necessary `wrangler.jsonc` configuration and a client-side `PartySocket` example."},"warnings":[{"fix":"If using `partysync`, update `Agent#connect(namespace, room)` calls to `Agent#connectTo(namespace, room)`.","message":"The method signature for `Agent#connect` in related package `partysync` (part of the broader PartyKit ecosystem) was renamed to `Agent#connectTo` to avoid collision with new TCP socket binding declarations in `@cloudflare/workers-types`.","severity":"breaking","affected_versions":"partysync@>=2.0.3"},{"fix":"Ensure both server and client libraries are up-to-date. If using `getServerByName`, it now calls `stub.setName()` via RPC, so custom stub creation might need adjustment.","message":"PartyServer changed its internal mechanism for passing room names and properties to Durable Objects from HTTP headers to RPC. This prevents sensitive data from appearing in logs but may break compatibility with older client implementations or custom routing logic that relied on header inspection.","severity":"breaking","affected_versions":"partyserver@>=0.4.1"},{"fix":"Add explicit `durable_objects` and `migrations` configurations to `wrangler.jsonc` as shown in the quickstart example, mapping `name` to your desired binding name and `class_name` to your exported `Server` class name.","message":"Unlike PartyKit, PartyServer does not automatically infer Durable Object bindings or migrations. You must manually define `durable_objects.bindings` and `migrations` in your `wrangler.jsonc` file for each Durable Object class.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Always use a compatible and recent version of `@cloudflare/workers-types` (e.g., `^4.20240729.0`) and TypeScript (`^5.0.0`) with PartyServer. Regularly update dependencies.","message":"Type errors can occur under newer `@cloudflare/workers-types` versions due to changes in how `fetch` and `ArrayBufferView` are handled. PartyServer aims to be compatible, but older versions might conflict.","severity":"gotcha","affected_versions":">=0.1.0"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"Add or correct the `durable_objects.bindings` entry in `wrangler.jsonc`, ensuring `name` matches the `env` property used in `fetch` and `class_name` matches your exported Durable Object class name.","cause":"The Durable Object binding for `MyServer` (or your equivalent class) is missing or incorrectly configured in `wrangler.jsonc`.","error":"Error: Durable Object binding \"MyServer\" not found. You must configure Durable Object bindings in wrangler.toml/wrangler.jsonc."},{"fix":"Ensure your Durable Object class explicitly `extends Server` from `partyserver`. Verify that `this` context is preserved in methods or use arrow functions for callbacks if necessary.","cause":"Your `Server` class likely doesn't extend `partyserver.Server`, or `this` context is lost in a callback.","error":"TypeError: 'this.broadcast is not a function' or 'this.room is undefined'"}],"ecosystem":"npm"}