Database
The recommended way to persist game data in Colyseus is @colyseus/database, the official persistence layer, built on Drizzle ORM. A single typed connection backs player accounts, cloud saves, leaderboards, live configs, analytics, moderation, and matchmaking.
A single GameDatabase instance exposes:
db.auth: user store for@colyseus/auth: bans, session revocation, password managementdb.saves: versioned cloud saves with optimistic lockingdb.leaderboards: keep-best scores, seasons, top-N and around-me queriesdb.configs: typed, hot-reloadable live-ops configurationdb.analytics/db.moderation/db.notes: event tracking, roles, and player notesdb.segments: declarative player cohorts for targetingDatabaseDriver: a matchmaking driver reusing the same connection
Colyseus itself remains database-agnostic: if your project needs a different stack, bring your own database and query it directly from your rooms.
@colyseus/database was introduced in Colyseus 0.18. Feedback is welcome on the public roadmap.
Installation
npm install --save @colyseus/databaseFor PostgreSQL, also install the postgres driver:
npm install --save postgresQuick start
Construct a GameDatabase and pass it to defineServer via the database option. The server boots the database (running migrations) before it starts listening, and automatically mounts the @colyseus/auth routes when that package is installed.
import { defineServer } from "colyseus";
import { GameDatabase } from "@colyseus/database";
export const db = new GameDatabase({
connectionString: process.env.DATABASE_URL,
});
export default defineServer({
database: db,
// ...rooms, routes, etc.
});Export the db instance so your rooms can import it. Inside any room lifecycle method, the services are ready to use:
import { Room } from "colyseus";
import { db } from "../app.config";
export class MyRoom extends Room {
async onJoin(client, options) {
// client.auth was populated by the default static onAuth,
// which already rejects banned/revoked tokens automatically.
await db.cloudSaves.load(client.auth.id);
}
}Dialects & connection strings
The dialect is auto-detected from the connection string. When omitted, SQLite is used with the default file colyseus.db.
| Connection string | Dialect | Notes |
|---|---|---|
(omitted) or ./game.db | SQLite | File-based; great for development |
:memory: | SQLite | Ephemeral; useful for tests |
postgres://… / postgresql://… | PostgreSQL | Production; requires the postgres package |
pglite://./data / pglite://:memory: | PGlite | Embedded Postgres, no external server |
// SQLite (development): defaults to colyseus.db
new GameDatabase();
// PostgreSQL (production)
new GameDatabase({ connectionString: process.env.DATABASE_URL });
// Embedded PGlite, file-backed
new GameDatabase({ dialect: "pglite", connectionString: "pglite://./data" });Migrations
The migrations option controls how the schema is applied at boot:
"auto"(default): creates missing tables and adds new columns. Idempotent and convenient for development."skip": does nothing; you manage the schema externally (e.g. adrizzle-kit migratestep in CI before the server starts).{ files: "./drizzle" }: runs SQL migration files generated bydrizzle-kit. Drizzle tracks applied migrations, so reruns are safe.
new GameDatabase({
connectionString: process.env.DATABASE_URL,
migrations: "skip", // schema applied by CI
});Matchmaking driver
Reuse the same connection as your matchmaking driver (one pool for everything, no separate Redis required):
import { defineServer } from "colyseus";
import { GameDatabase } from "@colyseus/database";
import { DatabaseDriver } from "@colyseus/database/driver";
export const db = new GameDatabase({ connectionString: process.env.DATABASE_URL });
export default defineServer({
database: db,
driver: new DatabaseDriver(), // adopts the GameDatabase connection
});Next steps
- Authentication: the built-in
@colyseus/authintegration (auto-mounted routes, ban gating, JWT revocation, admin helpers). - Services: cloud saves, leaderboards, live configs, analytics, moderation, notes, and the matching room plugins.
- Customizing built-in table schemas: extend the package’s drizzle tables with your own columns.
- Bring your own database: ORMs, query builders, Firebase, and the
onAuth/onLeaveintegration patterns.