Skip to main content

Node server in production

@rpgjs/server/node lets you run the RPGJS server runtime without Vite. If you want to structure an MMORPG project with a framework-agnostic src/server.ts plus host-specific entries such as Express, read /advanced/mmorpg-entries first. Use it when you want to mount the server in your own Node stack:
  • Express
  • Fastify
  • Hono on Node
  • a custom http.createServer() setup

Dev vs production

In development with @rpgjs/vite, map rooms are initialized automatically by the Vite plugin. In production, map updates must come from a trusted backend source. To protect /map/update, set RPGJS_MAP_UPDATE_TOKEN. When this environment variable is set:
  • gameplay clients cannot update maps
  • trusted backend code must send the token
  • you can use transport.updateMap() or call the HTTP endpoint yourself

1. Create the transport

2. Push trusted map updates

If your map data is produced inside the same trusted Node process, use transport.updateMap().
transport.updateMap("town", ...) targets the room map-town automatically.

3. Call /map/update from another trusted backend

If your editor pipeline, admin API, or deploy step runs outside the game server process, call the endpoint directly with the token. Endpoint format:
Example:
You can also send the token as:
  • x-rpgjs-map-update-token: <token>
  • Authorization: Bearer <token>
  1. Start your Node server with RPGJS_MAP_UPDATE_TOKEN set.
  2. Mount transport.handleNodeRequest() and transport.handleUpgrade().
  3. Keep initializeMaps: false in production.
  4. From a trusted backend source, call transport.updateMap() or POST /parties/main/map-<id>/map/update.
  5. Let gameplay clients use only normal movement and game actions.

WebSocket session ids

The Node transport is backed by @signe/room/node and follows the @signe/room session model:
  • conn.id is unique for each active WebSocket connection.
  • conn.sessionId is the stable private session id sent by the client.
provideMmorpg() sends this stable id through PartySocket, so a browser refresh or a second tab can restore the same player session without replacing the first active WebSocket. When you need to address or exclude a single physical socket, use conn.id; when you need to inspect the restored player session, use conn.sessionId.

Hono and other runtimes

The same transport can be used outside Express:
  • use transport.fetch() when your framework exposes Fetch Request/Response
  • use transport.handleNodeRequest() when your framework gives Node req/res
  • use transport.acceptWebSocket() or transport.handleUpgrade() for WebSocket upgrades

Security note

Do not expose /map/update without a token in public MMORPG production deployments. /map/update is a trusted server-side operation. It can redefine map geometry, events, and world metadata.

Development with Vite

With @rpgjs/vite, you do not need this manual flow for local development. The Vite plugin creates the transport internally and performs the server-side map bootstrap automatically.