ServerPresence

Presence

The Presence API is responsible for inter-process communication (IPC) when scaling Colyseus across multiple processes or machines. It provides pub/sub messaging and shared key-value storage that all server instances can access.

For single-process deployments, the default in-memory presence is sufficient. For multi-process or distributed deployments, you need an external presence (like Redis) so all server instances can communicate with each other.

Available Presence Options


Local Presence

The default presence used by Colyseus is LocalPresence, which stores all data in memory and only works within a single process. This is suitable for development and small-scale single-process applications.


Redis Presence

The RedisPresence uses Redis for pub/sub messaging and shared storage using ioredis. This is required for multi-process or distributed deployments.

npm install --save @colyseus/redis-presence

Basic Usage

app.config.ts
import { defineServer } from "colyseus";
import { RedisPresence } from "@colyseus/redis-presence";
 
const server = defineServer({
    presence: new RedisPresence(),
    // ...
});

Connection Options

The presence accepts multiple connection formats:

// Using a connection URL
new RedisPresence("redis://username:password@localhost:6379/0")
 
// Using a port number (connects to localhost)
new RedisPresence(6379)
 
// Using RedisOptions object
new RedisPresence({
    host: "localhost",
    port: 6379,
    password: "your-password",
    db: 0,
    // ... any ioredis options
})

See ioredis connection options for the full list of available options.

Redis Cluster

For high-availability setups, the presence supports Redis Cluster mode:

app.config.ts
import { defineServer } from "colyseus";
import { RedisPresence } from "@colyseus/redis-presence";
 
const server = defineServer({
    presence: new RedisPresence([
        { host: "node1.redis.example.com", port: 6379 },
        { host: "node2.redis.example.com", port: 6379 },
        { host: "node3.redis.example.com", port: 6379 },
    ], {
        // ClusterOptions (optional)
        redisOptions: { password: "your-password" }
    }),
    // ...
});

See ioredis Cluster documentation for all available cluster options.


Presence API

The Presence API is based on Redis’s data structures, providing key-value storage, pub/sub messaging, sets, hashes, and lists.

Every Room instance has a presence property:

MyRoom.ts
export class MyRoom extends Room {
    onCreate() {
        this.presence // Presence API is available 
    }
}

Alternatively, you can access matchMaker.presence from anywhere by importing the Match-maker API:

server.ts
import { matchMaker } from "colyseus";
 
matchMaker.presence // full Presence API is available from here

Pub/Sub Methods

subscribe

Subscribes to the given topic. The callback will be triggered whenever a message is published on that topic.

Signature
presence.subscribe(topic: string, callback: Function): Promise<Presence>
MyRoom.ts
this.presence.subscribe("global-event", (data) => {
    console.log("received message:", data);
});

unsubscribe

Unsubscribe from a given topic.

Signature
presence.unsubscribe(topic: string, callback?: Function): Promise<Presence>

Unsubscribe from all previously subscribed “global-event” callbacks.

MyRoom.ts
//
this.presence.unsubscribe("global-event");

publish

Posts a message to the given topic. All subscribers will receive the message.

Signature
presence.publish(topic: string, data: any): Promise<void>
MyRoom.ts
this.presence.publish("global-event", { any: 1, data: 2, here: "3" });

channels

Returns the list of active channels matching a pattern.

Signature
presence.channels(pattern?: string): Promise<string[]>
MyRoom.ts
// Get all channels
const allChannels = await this.presence.channels();
 
// Get channels matching a pattern
const gameChannels = await this.presence.channels("game:*");

Key-Value Methods

set

Set a key to hold a string value.

Signature
presence.set(key: string, value: string): Promise<void>
MyRoom.ts
await this.presence.set("global-key", "a string value");

setex

Set a key to hold a string value with an expiration time in seconds.

Signature
presence.setex(key: string, value: string, seconds: number): Promise<void>
MyRoom.ts
// Set a key that expires after 2 minutes
await this.presence.setex("global-key", "a string value", 120);

expire

Set a timeout on a key. After the timeout, the key will be automatically deleted.

Signature
presence.expire(key: string, seconds: number): Promise<void>
MyRoom.ts
await this.presence.set("global-key", "value");
await this.presence.expire("global-key", 60); // expires in 60 seconds

get

Get the value of a key.

Signature
presence.get(key: string): Promise<string | null>
MyRoom.ts
const value = await this.presence.get("global-key");

del

Delete a key.

Signature
presence.del(key: string): Promise<void>
MyRoom.ts
await this.presence.del("global-key");

exists

Check if a key exists.

Signature
presence.exists(key: string): Promise<boolean>
MyRoom.ts
const exists = await this.presence.exists("global-key");

incr

Increment the integer value of a key by one.

Signature
presence.incr(key: string): Promise<number>

If the key does not exist, it is set to 0 before performing the operation.

MyRoom.ts
await this.presence.incr("global-count");
await this.presence.incr("global-count");
await this.presence.incr("global-count");
 
const count = await this.presence.get("global-count");
console.log(count); // => "3"

decr

Decrement the integer value of a key by one.

Signature
presence.decr(key: string): Promise<number>

If the key does not exist, it is set to 0 before performing the operation.

MyRoom.ts
await this.presence.set("global-count", "10");
await this.presence.decr("global-count");
 
const count = await this.presence.get("global-count");
console.log(count); // => "9"

Set Methods

Sets are collections of unique string values.

sadd

Add a member to a set.

Signature
presence.sadd(key: string, value: any): Promise<void>

If the member already exists, it is ignored. If the key does not exist, a new set is created.

MyRoom.ts
await this.presence.sadd("global-set", "member-one");
await this.presence.sadd("global-set", "member-one"); // ignored, already exists
await this.presence.sadd("global-set", "member-two");

smembers

Get all members of a set.

Signature
presence.smembers(key: string): Promise<string[]>
MyRoom.ts
const members = await this.presence.smembers("global-set");
console.log(members); // => ["member-one", "member-two"]

sismember

Check if a value is a member of a set.

Signature
presence.sismember(key: string, member: string): Promise<number>

Returns 1 if the element is a member, 0 if not (or if the key does not exist).

MyRoom.ts
const isMember = await this.presence.sismember("global-set", "member-one");
if (isMember) {
    console.log("member-one is in the set");
}

srem

Remove a member from a set.

Signature
presence.srem(key: string, value: any): Promise<void>
MyRoom.ts
await this.presence.srem("global-set", "member-one");

scard

Get the number of members in a set (cardinality).

Signature
presence.scard(key: string): Promise<number>
MyRoom.ts
const count = await this.presence.scard("global-set");
console.log(count); // => 2

sinter

Get the intersection of multiple sets.

Signature
presence.sinter(...keys: string[]): Promise<string[]>
MyRoom.ts
await this.presence.sadd("set1", "a");
await this.presence.sadd("set1", "b");
await this.presence.sadd("set2", "b");
await this.presence.sadd("set2", "c");
 
const intersection = await this.presence.sinter("set1", "set2");
console.log(intersection); // => ["b"]

Hash Methods

Hashes are maps of field-value pairs, useful for storing objects.

hset

Set a field in a hash.

Signature
presence.hset(key: string, field: string, value: string): Promise<boolean>

Returns true if the field is new, false if it was updated.

MyRoom.ts
await this.presence.hset("player:123", "name", "John");
await this.presence.hset("player:123", "score", "100");

hget

Get the value of a field in a hash.

Signature
presence.hget(key: string, field: string): Promise<string | null>
MyRoom.ts
const name = await this.presence.hget("player:123", "name");
console.log(name); // => "John"

hgetall

Get all fields and values of a hash.

Signature
presence.hgetall(key: string): Promise<{ [field: string]: string }>
MyRoom.ts
const player = await this.presence.hgetall("player:123");
console.log(player); // => { name: "John", score: "100" }

hdel

Delete a field from a hash.

Signature
presence.hdel(key: string, field: string): Promise<boolean>

Returns true if the field was removed, false if the field did not exist.

MyRoom.ts
await this.presence.hdel("player:123", "score");

hlen

Get the number of fields in a hash.

Signature
presence.hlen(key: string): Promise<number>
MyRoom.ts
const fieldCount = await this.presence.hlen("player:123");
console.log(fieldCount); // => 2

hincrby

Increment the integer value of a hash field.

Signature
presence.hincrby(key: string, field: string, value: number): Promise<number>
MyRoom.ts
await this.presence.hset("player:123", "score", "100");
const newScore = await this.presence.hincrby("player:123", "score", 10);
console.log(newScore); // => 110

hincrbyex

Increment a hash field and set an expiration on the hash key.

Signature
presence.hincrbyex(key: string, field: string, value: number, expireInSeconds: number): Promise<number>

This is useful for rate limiting or temporary counters.

MyRoom.ts
// Increment and expire in 60 seconds
const count = await this.presence.hincrbyex("rate:user:123", "requests", 1, 60);
if (count > 100) {
    console.log("Rate limit exceeded");
}

List Methods

Lists are ordered collections of strings, supporting push/pop operations from both ends.

llen

Get the length of a list.

Signature
presence.llen(key: string): Promise<number>
MyRoom.ts
const length = await this.presence.llen("queue");

rpush

Append a value to the end of a list.

Signature
presence.rpush(key: string, value: string): Promise<number>

Returns the length of the list after the push.

MyRoom.ts
await this.presence.rpush("queue", "task1");
await this.presence.rpush("queue", "task2");

lpush

Prepend a value to the beginning of a list.

Signature
presence.lpush(key: string, value: string): Promise<number>

Returns the length of the list after the push.

MyRoom.ts
await this.presence.lpush("queue", "urgent-task");

rpop

Remove and return the last element of a list.

Signature
presence.rpop(key: string): Promise<string | null>
MyRoom.ts
const lastItem = await this.presence.rpop("queue");

lpop

Remove and return the first element of a list.

Signature
presence.lpop(key: string): Promise<string | null>
MyRoom.ts
const firstItem = await this.presence.lpop("queue");

brpop

Remove and return the last element of a list, or block until one is available.

Signature
presence.brpop(...args: any): Promise<[string, string] | null>

The last argument is the timeout in seconds. Returns null if the timeout is reached.

MyRoom.ts
// Block for up to 5 seconds waiting for an item
const result = await this.presence.brpop("queue", 5);
if (result) {
    const [key, value] = result;
    console.log("Got item:", value);
}