DEV Community

Alex Spinov
Alex Spinov

Posted on

PartyKit Has a Free API — Build Multiplayer Apps on Cloudflare

TL;DR

PartyKit is a platform for building real-time, collaborative, multiplayer applications. It runs on Cloudflare's edge network with a generous free tier — perfect for chat, cursors, games, and collaborative editing.

What Is PartyKit?

PartyKit makes multiplayer easy:

  • Edge-first — runs on Cloudflare Workers globally
  • Room-based — each "party" is a stateful room
  • Hibernation — WebSocket connections stay alive even when idle
  • Durable Objects — state persists between connections
  • Free tier — 100K requests/day, unlimited connections
  • Framework-agnostic — works with any frontend

Quick Start

npm create partykit@latest my-app
cd my-app
npx partykit dev
Enter fullscreen mode Exit fullscreen mode

Server (party/index.ts)

import type * as Party from "partykit/server";

export default class ChatRoom implements Party.Server {
  messages: string[] = [];

  constructor(readonly room: Party.Room) {}

  onConnect(conn: Party.Connection) {
    // Send chat history to new connections
    conn.send(JSON.stringify({ type: "history", messages: this.messages }));
  }

  onMessage(message: string, sender: Party.Connection) {
    const data = JSON.parse(message);
    this.messages.push(data.text);

    // Broadcast to everyone in the room
    this.room.broadcast(
      JSON.stringify({ type: "message", text: data.text, from: sender.id }),
      [sender.id] // exclude sender
    );
  }

  onClose(conn: Party.Connection) {
    this.room.broadcast(
      JSON.stringify({ type: "leave", userId: conn.id })
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Client

import PartySocket from "partysocket";

const socket = new PartySocket({
  host: "my-app.username.partykit.dev",
  room: "my-chat-room",
});

socket.addEventListener("message", (event) => {
  const data = JSON.parse(event.data);
  if (data.type === "message") {
    console.log(`${data.from}: ${data.text}`);
  }
});

socket.send(JSON.stringify({ text: "Hello everyone!" }));
Enter fullscreen mode Exit fullscreen mode

Live Cursors Example

// Server
export default class CursorRoom implements Party.Server {
  cursors = new Map<string, { x: number; y: number }>();

  onMessage(message: string, sender: Party.Connection) {
    const cursor = JSON.parse(message);
    this.cursors.set(sender.id, cursor);
    this.room.broadcast(message, [sender.id]);
  }

  onClose(conn: Party.Connection) {
    this.cursors.delete(conn.id);
    this.room.broadcast(JSON.stringify({ type: "leave", id: conn.id }));
  }
}
Enter fullscreen mode Exit fullscreen mode

PartyKit vs Alternatives

Feature PartyKit Socket.IO Liveblocks Pusher
Free tier 100K req/day Self-host 1K MAU 200K msg/day
Edge deployment ✅ Cloudflare
Persistent state ✅ DO
Hibernation N/A N/A
CRDT support ✅ Y.js
Deploy command npx partykit deploy Manual Managed Managed

Y.js Integration (CRDT)

import { onConnect } from "y-partykit";

export default class SyncRoom implements Party.Server {
  onConnect(conn: Party.Connection) {
    // Automatic Y.js document syncing!
    return onConnect(conn, this.room);
  }
}
Enter fullscreen mode Exit fullscreen mode

Deploy

npx partykit deploy
# Deployed to: https://my-app.username.partykit.dev
Enter fullscreen mode Exit fullscreen mode

Resources


Building collaborative apps that need web data? My Apify tools extract data from any website — feed it into your PartyKit rooms for real-time collaborative analysis. Questions? Email spinov001@gmail.com

Top comments (0)