MMORPG entries
When RPG_TYPE=mmorpg, RPGJS now treats your project as a multi-entry application:
- a browser client
- a framework-agnostic server module
- optional hosting adapters such as Express
Use this layout when you want to keep your game server portable across:
- Vite development
- Express in production
- another Node host such as Fastify or Hono
- a custom deployment target later
RPG_TYPE defaults to rpg when it is not set. If this is your first online
deployment, start with Put an MMORPG online, which covers
local verification, map publication, Node/Docker, and Cloudflare.
Recommended structure
Keep your game logic in src/server.ts, and put host-specific bootstraps in src/entries.
Role of each file:
src/client.ts: browser entry for mmorpg
src/server.ts: RPGJS server module, without express(), listen(), or platform code
src/entries/express.ts: Node entry that mounts src/server.ts in Express
src/standalone.ts: browser entry for RPG_TYPE=rpg
Declare the MMORPG entries explicitly in your Vite config.
Keep src/server.ts agnostic
src/server.ts should export your RPGJS server module and nothing else.
It should not:
- create an HTTP server
- call
listen()
- import Express directly
- depend on a specific host runtime
Example:
This file is the canonical server entry for your game. Vite development can use it directly, and production adapters can import it without duplicating game setup.
Express adapter example
Put your Express bootstrap in src/entries/express.ts.
This adapter is responsible for:
- serving the built client from
dist/client
- forwarding HTTP requests under
/parties
- forwarding WebSocket upgrades to the RPGJS transport
Build output
Run the MMORPG build with:
RPGJS produces two output folders:
Meaning of each output:
dist/client: browser assets containing client and explicitly shared modules
dist/server/server.js: built version of your agnostic src/server.ts
dist/server/express.js: built version of your Express adapter
The MMORPG client build does not include modules imported only by
src/server.ts. Conversely, client-only modules and components are not part of
the server entry. Files imported by both entry graphs are shared code and may be
present in both outputs.
Do not import a server module, a server adapter, or a combined module index from
the client entry graph. Any file reachable from browser code can be included in
dist/client. Keep secrets in the deployment environment, never in source code
that a browser build can reach.
Keep source maps server-side
Map assets follow the same entry boundary as modules. In MMORPG mode, install the
server side of a map provider in src/server.ts; its compiler reads the complete
map and streams only nearby render and prediction chunks. The client side applies
those chunks but does not fetch the source document.
For Tiled, expose image files through tiledMapFolderPlugin() and omit .tmx and
.tsx from allowedExtensions. Event definitions, object properties, collision
rules and the raw tile layer stay in the map room. The same provider module works
with a Node.js transport or a Cloudflare Durable Object.
Start the built Express server with:
Development flow
During development, Vite still uses the server module you pass to rpgjs({ server }).
That means:
src/server.ts stays the single source of truth for your game server
- your adapter files are only needed when you want a specific production host
- you do not need a separate
server-dev.ts
Add another host later
To support another runtime, keep src/server.ts unchanged and add another adapter file:
src/entries/fastify.ts
src/entries/hono.ts
src/entries/custom.ts
Then declare it in entryPoints.mmorpg.adapters.
The build will emit one file per adapter in dist/server.
Related pages