Skip to main content

Documentation 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 ships two routing utilities that bridge incoming Worker requests to named Server Durable Objects. routePartykitRequest handles URL-based routing for both WebSocket and HTTP requests following the /:prefix/:party/:name convention. getServerByName lets you obtain a Durable Object stub directly by name when you want to address a server from within your own routing logic.

routePartykitRequest

async function routePartykitRequest<
  Env extends Cloudflare.Env = Cloudflare.Env,
  T extends Server<Env> = Server<Env>,
  Props extends Record<string, unknown> = Record<string, unknown>
>(
  req: Request,
  env: Env,
  options?: PartyServerOptions<Env, Props>
): Promise<Response | null>
Match an incoming Request against the URL pattern /${prefix}/:party/:name and forward it to the matching Durable Object namespace. Returns null when the URL does not match, so you can chain it with your own fallback handler. Namespace matching is case-insensitive and kebab-case aware: a binding named MyServer in wrangler.jsonc is matched by the URL segment my-server.
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    return (
      (await routePartykitRequest(request, env)) ??
      new Response("Not Found", { status: 404 })
    );
  }
} satisfies ExportedHandler<Env>;
return
Promise<Response | null>
A Response when the URL matched a known namespace and the request was forwarded, or null when no match was found. Also returns a 400 Bad Request response when the URL matches the prefix pattern but references an unknown namespace.

Options

prefix
string
default:"parties"
The URL path prefix to match. Requests must start with /${prefix}/:party/:name. Supports multi-segment prefixes like "api/rooms".
locationHint
DurableObjectLocationHint
Preferred location hint for where the Durable Object should be placed (e.g. "wnam", "eeur"). Only applies to new objects — existing objects stay in their current location.
jurisdiction
DurableObjectJurisdiction
Restrict the Durable Object to a specific jurisdiction for data residency compliance (e.g. "eu").
props
Props
Arbitrary JSON-serializable properties to deliver to the server’s onStart hook. Encoded in the x-partykit-props request header and decoded inside the DO.
cors
boolean | HeadersInit
Enable CORS for matched routes.
routingRetry
RoutingRetryOptions | false
Control retry behavior for transient Durable Object infrastructure errors. Enabled by default with 3 attempts and jittered exponential backoff. Pass false to disable retries entirely. See RoutingRetryOptions.
onBeforeConnect
(req: Request, lobby: Lobby) => Request | Response | void | Promise<...>
Intercept WebSocket upgrade requests before they reach the server. Called only for requests with an Upgrade: websocket header.
onBeforeConnect: async (req, lobby) => {
  const token = req.headers.get("Authorization");
  if (!isValid(token)) {
    return new Response("Unauthorized", { status: 401 });
  }
}
onBeforeRequest
(req: Request, lobby: Lobby) => Request | Response | void | Promise<...>
Intercept plain HTTP requests before they reach the server’s onRequest handler. Behaves identically to onBeforeConnect but fires for non-WebSocket requests.

The Lobby object

Both onBeforeConnect and onBeforeRequest receive a lobby argument:
interface Lobby<Env = Cloudflare.Env> {
  /** The Durable Object class name / env binding name (e.g. "MyServer"). */
  className: Extract<keyof Env, string>;
  /** The room / instance name extracted from the URL. */
  name: string;
  /** @deprecated Use className instead. Returns the kebab-case namespace. */
  party: string;
}
lobby.className
string
The original Durable Object binding name as declared in wrangler.jsonc (e.g. "MyServer").
lobby.name
string
The server instance name extracted from the URL (the :name segment).

getServerByName

async function getServerByName<
  Env extends Cloudflare.Env = Cloudflare.Env,
  T extends Server<Env> = Server<Env>,
  Props extends Record<string, unknown> = Record<string, unknown>
>(
  serverNamespace: DurableObjectNamespace<T>,
  name: string,
  options?: {
    jurisdiction?: DurableObjectJurisdiction;
    locationHint?: DurableObjectLocationHint;
    props?: Props;
    routingRetry?: false | RoutingRetryOptions;
  }
): Promise<DurableObjectStub<T>>
Directly address a named Server Durable Object without going through URL routing. Returns a DurableObjectStub you can call fetch() or RPC methods on. Before returning, getServerByName performs an RPC that awaits the server’s onStart() hook, so you can immediately invoke user-defined RPC methods on the stub and trust that initialization has completed.
import { getServerByName } from "partyserver";

// Inside a Worker fetch handler:
const stub = await getServerByName(env.MyServer, "room-42");
const response = await stub.fetch(request);
serverNamespace
DurableObjectNamespace<T>
The Durable Object namespace binding from your env. Must correspond to a class that extends Server.
name
string
The logical name of the server instance. Used as the Durable Object ID name.
options.locationHint
DurableObjectLocationHint
Preferred geographic location for the Durable Object. Only affects placement of new objects.
options.jurisdiction
DurableObjectJurisdiction
Data residency jurisdiction restriction (e.g. "eu").
options.props
Props
Initial properties passed to the server’s onStart hook on first wake.
options.routingRetry
RoutingRetryOptions | false
Retry options for transient infrastructure errors. See RoutingRetryOptions. Pass false to disable retries.
return
Promise<DurableObjectStub<T>>
A stub pointing to the named Durable Object, after onStart() has completed.

RoutingRetryOptions

Both routePartykitRequest and getServerByName support automatic retries for transient Durable Object infrastructure errors. Only errors with retryable === true are retried. Errors with overloaded === true are never retried regardless of other settings.
interface RoutingRetryOptions {
  maxAttempts?: number;
  baseDelayMs?: number;
  maxDelayMs?: number;
  onRetry?: (event: RoutingRetryEvent) => void | Promise<void>;
}
maxAttempts
number
default:"3"
Maximum number of attempts, including the first try. Must be an integer ≥ 1.
baseDelayMs
number
default:"100"
Base delay in milliseconds for exponential backoff. Each retry waits a random duration up to min(maxDelayMs, baseDelayMs × 2^(attempt-1)). Must be > 0.
maxDelayMs
number
default:"800"
Upper cap in milliseconds for the jittered backoff delay. Must be ≥ baseDelayMs.
onRetry
(event: RoutingRetryEvent) => void | Promise<void>
Optional callback invoked before each retry delay. Useful for logging or metrics.
Custom retry configuration:
await routePartykitRequest(request, env, {
  routingRetry: {
    maxAttempts: 5,
    baseDelayMs: 50,
    maxDelayMs: 2000,
    onRetry: ({ attempt, delayMs, name }) => {
      console.warn(`Retry ${attempt} for server "${name}", waiting ${delayMs}ms`);
    }
  }
});
Disable retries:
await routePartykitRequest(request, env, { routingRetry: false });

Complete routing example

import { routePartykitRequest, getServerByName } from "partyserver";

interface Env {
  ChatServer: DurableObjectNamespace;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // 1. URL-based routing with auth guard and CORS
    const response = await routePartykitRequest(request, env, {
      prefix: "rooms",
      cors: true,
      async onBeforeConnect(req, lobby) {
        const token = req.headers.get("Authorization");
        if (!token) return new Response("Unauthorized", { status: 401 });
        // Return a modified request with the verified user ID attached
        const headers = new Headers(req.headers);
        headers.set("x-user-id", await verifyToken(token));
        return new Request(req, { headers });
      }
    });

    if (response) return response;

    // 2. Direct server access by name (e.g. from an admin endpoint)
    if (new URL(request.url).pathname === "/admin/ping") {
      const stub = await getServerByName(env.ChatServer, "main-lobby");
      return stub.fetch(request);
    }

    return new Response("Not Found", { status: 404 });
  }
} satisfies ExportedHandler<Env>;

async function verifyToken(token: string): Promise<string> {
  // your auth logic
  return "user-123";
}

Build docs developers (and LLMs) love