ServerHTTP Routes

HTTP Routes

Colyseus provides two ways to add HTTP endpoints to your server:

  • API Routes (recommended) — Type-safe, with validation, middleware, frontend SDK integration, and visual testing via the Playground.
  • Express — Use if you rely on existing Express middleware or libraries.

API Routes

Define type-safe HTTP endpoints using createEndpoint and createRouter.

app.config.ts
import { defineServer, createEndpoint, createRouter } from "colyseus";
import { z } from "zod";
 
const getProfile = createEndpoint("/profile/:id", {
    method: "GET",
    query: z.object({ include: z.string().optional() }),
}, async (ctx) => {
    return {
        id: ctx.params.id,
        include: ctx.query.include,
    };
});
 
const updateProfile = createEndpoint("/profile/:id", {
    method: "POST",
    body: z.object({ name: z.string() }),
}, async (ctx) => {
    ctx.setStatus(201);
    return { id: ctx.params.id, name: ctx.body.name };
});
 
const server = defineServer({
    routes: createRouter({
        getProfile,
        updateProfile,
    })
});

Middleware

Use createMiddleware to share logic across endpoints. The returned context is merged into ctx.context.

import { createEndpoint, createMiddleware } from "colyseus";
 
const auth = createMiddleware(async (ctx) => {
    const token = ctx.headers.get("authorization");
    if (!token) throw ctx.error("UNAUTHORIZED", { message: "Missing token" });
    return { userId: "user-123" };
});
 
export const secureEndpoint = createEndpoint("/secure", {
    method: "GET",
    use: [auth],
}, async (ctx) => {
    ctx.setHeader("X-User", ctx.context.userId);
    ctx.setCookie("session", "abc", { httpOnly: true });
    return { ok: true, userId: ctx.context.userId };
});

Endpoint Options

createEndpoint(path, options, handler) accepts the following options:

OptionDescription
methodHTTP method string or array (e.g. "GET" or ["GET", "POST"]).
bodyZod schema for request body validation. Invalid bodies return 400.
queryZod schema for query string validation. Invalid queries return 400.
useArray of middlewares created with createMiddleware.
requireHeadersWhen true, requires headers when calling the endpoint as a function.
requireRequestWhen true, requires a request object when calling the endpoint as a function.
metadata.scope"rpc" (default): available to RPC client. "server": callable directly only. "http": routed only.
metadata.allowedMediaTypesRestricts accepted Content-Type values for this endpoint.

Handler Context

The handler signature is async (ctx) => response.

Properties

PropertyDescription
ctx.requestThe raw Request object (when running via HTTP).
ctx.headersHeaders instance for the incoming request.
ctx.bodyParsed and validated request body.
ctx.queryParsed and validated query string.
ctx.paramsRoute parameters (e.g. :id, **:name).
ctx.methodHTTP method (useful for multi-method endpoints).
ctx.contextMerged middleware context.

Methods

MethodDescription
ctx.setStatus(status)Override the default success status code.
ctx.error(codeOrStatus, data?, headers?)Throw an API error.
ctx.redirect(url)Throw a redirect response.
ctx.json(data)Return a JSON response.
ctx.setHeader(name, value)Set a response header.
ctx.setCookie(name, value, options?)Set a response cookie.
ctx.getCookie(name)Read a request cookie.
ctx.setSignedCookie(name, value, options?)Set a signed cookie.
ctx.getSignedCookie(name)Read a signed cookie.

Express Routes

Use Express if you rely on existing Express middleware or libraries.

app.config.ts
import { defineServer } from "colyseus";
import express from "express";
 
const server = defineServer({
    // ...
    express: (app) => {
        app.use(express.json({ limit: "100kb" }));
 
        app.get("/hello", (req, res) => {
            res.json({ hello: "world" });
        });
 
        app.post("/profile", (req, res) => {
            res.json({ received: req.body });
        });
    },
    // ...
});

See the Express routing guide for more details.


CORS

CORS is enabled by default. You can customize the headers:

import { matchMaker } from "colyseus";
 
matchMaker.controller.DEFAULT_CORS_HEADERS = {
    'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept, Authorization',
    'Access-Control-Allow-Methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
    'Access-Control-Allow-Credentials': 'true',
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Max-Age': '2592000',
    // ...
}

You can also return custom CORS headers based on the request:

import { matchMaker } from "colyseus";
 
matchMaker.controller.getCorsHeaders = function(requestHeaders) {
    // check for 'requestHeaders' and return custom key-value headers here.
    return {};
}

See MDN documentation on CORS for more information.


Frontend Usage

Use client.http.* methods to call your HTTP endpoints from the frontend.

See Client SDK → HTTP Requests for the full API reference.