If you built an app on the original PartyKit.io hosted platform, you can migrate it to run on your own Cloudflare Workers account using the open-sourceDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/cloudflare/partykit/llms.txt
Use this file to discover all available pages before exploring further.
partyserver and partysocket packages. The server-side API is intentionally similar — most lifecycle hooks keep the same names — but there are a handful of structural differences to be aware of.
The original PartyKit.io platform and these open-source libraries (
partyserver, partysocket, y-partyserver, etc.) are separate projects. The libraries let you host the same real-time patterns on your own Cloudflare account without depending on the PartyKit.io service.Key differences
1. URL routing is decoupled
PartyKit.io automatically inferred Durable Object routing from the URL pattern/parties/:server/:room. partyserver does not do this by default — the URL shape and the DO namespace are decoupled.
To get the same /parties/:server/:name routing you are used to, call routePartykitRequest in your Worker’s fetch handler:
routePartykitRequest matches requests of the form /${prefix}/:server/:name (the prefix defaults to "parties") and routes them to the Durable Object namespace whose binding name matches :server (case-insensitive).
2. No auto-inferred Durable Object declarations
PartyKit.io inferred Durable Object bindings and migrations from your source code. Withpartyserver you must declare them manually in wrangler.jsonc:
3. No built-in AI, KV, or static asset bindings
PartyKit.io provided shorthand configuration for AI, KV, R2, and static asset bindings. In a standard Cloudflare Worker you add these throughwrangler.jsonc’s native binding sections ([[kv_namespaces]], [[r2_buckets]], [ai], etc.) and then access them via this.env inside your server.
4. The server name comes from ctx.id.name
In partyserver, this.name on a Server instance resolves from the underlying Durable Object’s ctx.id.name. This is populated whenever the DO is addressed via idFromName() — which is the normal path taken by routePartykitRequest.
Migration steps
Update your server class
Change Key changes:
extends Party (the PartyKit.io class) to extends Server from partyserver. The lifecycle hook names are the same.- Extend
Serveras a class (noimplementsinterface or constructor injection) - Use
this.nameinstead ofthis.party.id - Use
this.broadcast(...)instead ofthis.party.broadcast(...) - Use
this.envinstead ofthis.party.env
Add a fetch handler with routePartykitRequest
Add a default export with a
fetch handler that delegates to routePartykitRequest. This replaces PartyKit.io’s built-in URL routing.Configure wrangler.jsonc
Add the Durable Object binding and a migration for each server class.The binding name must match the class name exactly (case-sensitive).
routePartykitRequest matches the URL segment :server case-insensitively, so a request to /parties/my-server/room-1 will route to the MyServer binding.Lifecycle hook compatibility
All standard PartyKit.io lifecycle hooks are available inpartyserver with the same names:
| Hook | Description |
|---|---|
onStart() | Called when the server starts or wakes from hibernation |
onConnect(connection, context) | New WebSocket connection established |
onMessage(connection, message) | Message received from a client |
onClose(connection, code, reason, wasClean) | Client closed the connection |
onError(connection, error) | Error on a connection |
onRequest(request) | HTTP request to the server |
onAlarm() | Durable Object alarm fired |
URL compatibility
routePartykitRequest reproduces the same /parties/:server/:name URL pattern that PartyKit.io used. No changes to client URL construction are required as long as you pass the same host, party, and room values.
If you need a different URL prefix (e.g. /rooms/) you can configure it: