FAQ

Frequently Asked Questions

Performance & Scaling

How many CCU can a Colyseus server handle?

The maximum number of concurrent users (CCU) a Colyseus server can handle depends on several factors:

  • CPU: How intensive your game loop and message handlers are. Complex physics or AI calculations will limit CCU.
  • RAM: Each connection and room state consumes memory. A typical connection uses ~2-5KB, but this grows with your state size. Monitor memory usage to avoid OOM crashes.
  • Bandwidth: The frequency and size of state patches sent to clients. Use State View to reduce per-client traffic.
  • File descriptors: Linux servers default to ~1024 open connections. This can be increased via ulimit -n (e.g., ulimit -n 65535), but ensure your hardware can handle the load.

As a baseline, a small cloud server (1 vCPU, 1GB RAM) can typically handle 1,000-2,000 concurrent connections for simple games. For complex games with large state, expect fewer. Always load test your specific use case.

How can I improve performance?

  • Reduce state size: Only include data that needs to be synchronized. Use messages for transient data.
  • Optimize patch rate: The default patchRate is 50ms. Increase it if your game doesn’t need frequent updates.
  • Use State View: Limit what each client sees using State View to reduce bandwidth per client.
  • Profile your room code: Avoid heavy computations.

Does Colyseus help me with client-prediction?

Not yet—client-prediction is planned for a future release (see Roadmap). For now, see our Phaser tutorial for a reference implementation.


Connection Issues

I’m getting "Error: seat reservation expired", what does it mean?

This error means that the client was not able to effectively connect with the server’s room in time.

This error may appear in a few scenarios:

  • Server is under heavy load and by the time it can respond to a WebSocket connection request, the “seat reservation” code has already expired. You may increase the seat reservation time limit to remedy this.
  • You have mixed Colyseus package versions in your package.json. (between 0.14.x and 0.15.x, for example) Make sure to only use packages under 0.15.x (if you are using version 0.15), OR 0.14.x (if you are using version 0.14) - the exact patch version does not matter, but major and minor matters.
  • When using multiple Node.js processes, your scalability configuration may not be correct. Make sure to follow scalability instructions.

How do I handle reconnection?

When a client disconnects (e.g., closed browser tab), you can allow them to reconnect to the same room:

  1. Store the room.reconnectionToken on the client after joining
  2. Use client.reconnect(reconnectionToken) to rejoin
  3. On the server, set allowReconnection in onLeave:
import { CloseCode } from "colyseus";
// ...
 
async onLeave(client, code) {
    if (code !== CloseCode.CONSENTED) {
        // Allow reconnection for 30 seconds
        await this.allowReconnection(client, 30);
    }
}

State Synchronization

Why is my room state not synchronizing with the client?

If you are using TypeScript to target ES2022/ESNext, you need to provide "useDefineForClassFields": false on your tsconfig to make sure @type() decorators are defining property accessors properly.

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

See colyseus/colyseus#510 for more details.

How can I sync data only to a specific client?

Support for per-client state visibility was introduced in version 0.16. You can use the StateView class to control which parts of the state are visible to each client. See State View for more details.

When should I use state vs messages?

Use State when…Use Messages when…
Data needs to persistEvent is one-time
All/new clients need the valueOnly current clients care
Data changes frequentlyTriggering an action/effect
Example: positions, scoresExample: chat, events

TypeScript Errors

I’m getting this error: Class constructor Room cannot be invoked without 'new'", what should I do?

Make sure you have es2015 or higher in your tsconfig.json:

tsconfig.json
{
    "compilerOptions": {
        "target": "es2015"
    }
}

TypeScript decorators aren’t working

Ensure these settings in your tsconfig.json:

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

Unity SDK

Unity WebSocket connection drops during debugging

If you set a breakpoint in your application while the WebSocket connection is open, the connection will be closed automatically after 3 seconds due to inactivity. To prevent this, use pingInterval: 0 during development:

app.config.ts
import { defineServer } from "colyseus";
import { WebSocketTransport } from "@colyseus/ws-transport";
 
const server = defineServer({
    transport: new WebSocketTransport({
        pingInterval: 0, // Disable for debugging
    }),
});
⚠️

Remember to set pingInterval back to a positive value (default: 3000) in production.

How do I test multiple Unity clients locally?

Starting with Unity 6000.1.0b1, use Multiplayer Play Mode. For older versions, use ParrelSync.


Rooms & Architecture

When should I create separate room types?

Create separate room types when:

  • Different game modes have different logic (e.g., BattleRoom, LobbyRoom)
  • Different state structures are needed
  • Different max players or configurations

Reuse room types when:

  • The same game can have multiple instances (most common case)
  • Only configuration differs (pass options on join)

Can rooms communicate with each other?

Yes, using Presence. Rooms can publish/subscribe to channels to coordinate across instances:

// In Room A
this.presence.publish("game-events", { type: "tournament-start" });
 
// In Room B
this.presence.subscribe("game-events", (message) => {
    console.log("Received:", message);
});

How do I persist room data?

Rooms are ephemeral by default. To persist data:

  • Use a database (Postgres, MongoDB, Redis) to save game state
  • Load state in onCreate(), save in onDispose()
  • See Database for integration guides