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-presenceBasic Usage
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:
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:
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:
import { matchMaker } from "colyseus";
matchMaker.presence // full Presence API is available from herePub/Sub Methods
subscribe
Subscribes to the given topic. The callback will be triggered whenever a message is published on that topic.
presence.subscribe(topic: string, callback: Function): Promise<Presence>this.presence.subscribe("global-event", (data) => {
console.log("received message:", data);
});unsubscribe
Unsubscribe from a given topic.
presence.unsubscribe(topic: string, callback?: Function): Promise<Presence>Unsubscribe from all previously subscribed “global-event” callbacks.
//
this.presence.unsubscribe("global-event");publish
Posts a message to the given topic. All subscribers will receive the message.
presence.publish(topic: string, data: any): Promise<void>this.presence.publish("global-event", { any: 1, data: 2, here: "3" });channels
Returns the list of active channels matching a pattern.
presence.channels(pattern?: string): Promise<string[]>// 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.
presence.set(key: string, value: string): Promise<void>await this.presence.set("global-key", "a string value");setex
Set a key to hold a string value with an expiration time in seconds.
presence.setex(key: string, value: string, seconds: number): Promise<void>// 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.
presence.expire(key: string, seconds: number): Promise<void>await this.presence.set("global-key", "value");
await this.presence.expire("global-key", 60); // expires in 60 secondsget
Get the value of a key.
presence.get(key: string): Promise<string | null>const value = await this.presence.get("global-key");del
Delete a key.
presence.del(key: string): Promise<void>await this.presence.del("global-key");exists
Check if a key exists.
presence.exists(key: string): Promise<boolean>const exists = await this.presence.exists("global-key");incr
Increment the integer value of a key by one.
presence.incr(key: string): Promise<number>If the key does not exist, it is set to 0 before performing the operation.
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.
presence.decr(key: string): Promise<number>If the key does not exist, it is set to 0 before performing the operation.
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.
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.
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.
presence.smembers(key: string): Promise<string[]>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.
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).
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.
presence.srem(key: string, value: any): Promise<void>await this.presence.srem("global-set", "member-one");scard
Get the number of members in a set (cardinality).
presence.scard(key: string): Promise<number>const count = await this.presence.scard("global-set");
console.log(count); // => 2sinter
Get the intersection of multiple sets.
presence.sinter(...keys: string[]): Promise<string[]>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.
presence.hset(key: string, field: string, value: string): Promise<boolean>Returns true if the field is new, false if it was updated.
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.
presence.hget(key: string, field: string): Promise<string | null>const name = await this.presence.hget("player:123", "name");
console.log(name); // => "John"hgetall
Get all fields and values of a hash.
presence.hgetall(key: string): Promise<{ [field: string]: string }>const player = await this.presence.hgetall("player:123");
console.log(player); // => { name: "John", score: "100" }hdel
Delete a field from a hash.
presence.hdel(key: string, field: string): Promise<boolean>Returns true if the field was removed, false if the field did not exist.
await this.presence.hdel("player:123", "score");hlen
Get the number of fields in a hash.
presence.hlen(key: string): Promise<number>const fieldCount = await this.presence.hlen("player:123");
console.log(fieldCount); // => 2hincrby
Increment the integer value of a hash field.
presence.hincrby(key: string, field: string, value: number): Promise<number>await this.presence.hset("player:123", "score", "100");
const newScore = await this.presence.hincrby("player:123", "score", 10);
console.log(newScore); // => 110hincrbyex
Increment a hash field and set an expiration on the hash key.
presence.hincrbyex(key: string, field: string, value: number, expireInSeconds: number): Promise<number>This is useful for rate limiting or temporary counters.
// 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.
presence.llen(key: string): Promise<number>const length = await this.presence.llen("queue");rpush
Append a value to the end of a list.
presence.rpush(key: string, value: string): Promise<number>Returns the length of the list after the push.
await this.presence.rpush("queue", "task1");
await this.presence.rpush("queue", "task2");lpush
Prepend a value to the beginning of a list.
presence.lpush(key: string, value: string): Promise<number>Returns the length of the list after the push.
await this.presence.lpush("queue", "urgent-task");rpop
Remove and return the last element of a list.
presence.rpop(key: string): Promise<string | null>const lastItem = await this.presence.rpop("queue");lpop
Remove and return the first element of a list.
presence.lpop(key: string): Promise<string | null>const firstItem = await this.presence.lpop("queue");brpop
Remove and return the last element of a list, or block until one is available.
presence.brpop(...args: any): Promise<[string, string] | null>The last argument is the timeout in seconds. Returns null if the timeout is reached.
// 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);
}