Getting StartedTypeScript TypeScript

TypeScript SDK

The JavaScript/TypeScript SDK is engine agnostic and can be used with any game engine or framework that supports WebSockets, such as:

  • Modern web browsers (and mobile web browsers)
  • Node.js
  • Bun
  • Electron
  • React Native
  • Engines/Frameworks: Phaser, PlayCanvas, React, Pixi.js, Babylon.js, THREE.js, KAPLAY, etc.

Installation

npm install --save @colyseus/sdk

The SDK includes TypeScript definitions, so you get full type support out of the box.

Initializing the SDK

import { Client } from "@colyseus/sdk";
 
const client = new Client("http://localhost:2567");

Full Type Safety: Room State and Messages

It is recommended to provide the typeof server type as a generic to the client. This will allow the client to infer both the state type, and the message types for the room.

import { Client } from "@colyseus/sdk";
import type { server } from "../../server/src/app.config.ts";
 
const client = new Client<typeof server>("http://localhost:2567");

import type only imports type information at compile time—no server code is included in your client bundle.

Providing Room State Types

There are two ways to get type safety for your room’s state:

Option 1: Importing the Room State Type Only

Use import type to import the state type and pass it as a generic to joinOrCreate<T>(). This gives you type inference for room.state and state callbacks.

This way, you don’t get type inference for the message name or the payload type.

import { Client } from "@colyseus/sdk";
import type { MyState } from "../server/rooms/schema/MyState";
 
const client = new Client("http://localhost:2567");
const room = await client.joinOrCreate<MyState>("my_room");
 
room.state.players  // ✓ Auto-complete works
room.state.invalid  // ✗ Compile error
 
room.onMessage("...", (client, payload) => {}); // ?? Missing type here!
Option 2: Importing the Room Type Only

Use import type and pass the type as a generic to joinOrCreate<T>(). This gives you type inference for room.state and state callbacks.

import { Client } from "@colyseus/sdk";
import type { MyRoom } from "../server/rooms/MyRoom";
 
const client = new Client("http://localhost:2567");
const room = await client.joinOrCreate<MyRoom>("my_room");
 
room.state.players  // ✓ Auto-complete works
room.state.invalid  // ✗ Compile error
 
room.onMessage("...", () => {}); // ✓ Type-safe

Sharing Schema Classes with the Client

If you import the actual schema class (not just its type) and pass it as the third argument to joinOrCreate(), you get two benefits:

  1. Custom methods available — Any custom methods you’ve defined on your schema classes become accessible on the client.
  2. Reduced bandwidth — The server skips sending the state structure definition when the client joins, since the client already knows the schema shape.
import { Client } from "@colyseus/sdk";
import { MyState } from "../server/rooms/MyState";
 
const client = new Client("http://localhost:2567");
const room = await client.joinOrCreate("my_room", {}, MyState);
 
room.state.players  // ✓ Auto-complete works
room.state.players.get("abc")?.customMethod()  // ✓ Custom methods available

Room Debug Panel

The debug panel allows you to inspect the room state and messages in real-time during development, simulate high latency conditions, connection drops, and more.

You can enable the Room Debug Panel in development mode by:

import "@colyseus/sdk/debug";


Troubleshooting: tsconfig.json Configuration

If you’re using ES2022 or ESNext and experiencing issues with state synchronization, ensure your tsconfig.json includes:

tsconfig.json
{
    "compilerOptions": {
        "useDefineForClassFields": false,
        "experimentalDecorators": true,
        "strict": true
    }
}

This is required for the @type() decorators to work correctly in Schema classes.

Next Steps

Last updated on