Configuration

XMS: XyPriss Multi-Server Orchestration

Run multiple isolated server instances within a single Node.js process, each with independent ports, security policies, caching strategies, and route scopes while sharing the same underlying system resources.

Why XMS?

Process Efficiency

Shared memory and system overhead compared to running multiple independent Node.js processes.

Network Isolation

Different security levels for Admin vs Public APIs on distinct ports within the same process.

Unified Lifecycle

Start, stop, and monitor all services from a single entry point. One app.start() boots all configured instances.

Route Scoping

Granular control over which routes are served by which instance via allowedRoutes and prefix strategies.

Server Configuration

XMS is configured programmatically via the ServerOptions passed to createServer. Each entry in the servers array supports the following properties:

PropertyTypeDescription
idstringRequired. Unique identifier for the server instance (used in logs).
portnumberRequired. The port the instance will listen on.
hoststringHost address (default: 127.0.0.1).
routePrefixstringA prefix to filter or inject into routes handled by this instance.
routePrefixStrategystringPrefix handling: auto-inject (default), strict-match, or both.
allowedRoutesstring[]Patterns of routes this instance is allowed to serve (e.g., ["/api/*", "/login"]).
responseControlobjectCustom behaviour for unhandled routes on this instance.
...ServerOptionsanyAny other ServerOptions (security, cache, fileUpload, etc.) to override per instance.
typescript
import { createServer } from "xypriss";

const app = createServer({
  multiServer: {
    enabled: true,
    servers: [
      {
        id: "public-api",
        port: 8080,
        routePrefix: "/api/v1",
        routePrefixStrategy: "auto-inject",
        allowedRoutes: ["/api/*"],
        host: "0.0.0.0"
      },
      {
        id: "admin-panel",
        port: 8081,
        routePrefix: "/admin",
        security: { csrf: true, helmet: true }
      }
    ]
  }
});

Global Configuration Merging

XyPriss implements a Global Merge Rule to reduce configuration redundancy. Options defined at the root of the ServerOptions object are treated as global defaults for all server instances.

The merge strategy is deep: nested objects like security.helmet or logger.format are intelligently combined. Server-level options always take precedence over root-level globals.

typescript
const app = createServer({
  // --- GLOBAL SETTINGS ---
  // All servers will use 'debug' level and have CSRF enabled
  logger: { level: "debug" },
  security: { csrf: true },

  multiServer: {
    enabled: true,
    servers: [
      {
        id: "public",
        port: 8080
        // Inherits: logger { level: "debug" }, security { csrf: true }
      },
      {
        id: "internal",
        port: 8081,
        logger: { level: "info" } // Overrides global logger level
        // Inherits: security { csrf: true }
      }
    ]
  }
});
Deep Merge Precedence
Root-level global options are merged first, then per-server overrides are applied. For objects, only the explicitly provided keys override — sibling keys remain inherited from the global config.

Route Orchestration

Control how routes are distributed across instances using the routePrefixStrategy and allowedRoutes properties.

auto-inject

If a route is /login and the server has a prefix /auth, it will be served at /auth/login on that instance.

strict-match

Only routes explicitly registered with the prefix (e.g., app.get("/auth/login")) are served.

both

The route is served at both its original path and the prefixed path.

Instance-Level Response Control

You can define what happens when a request hits a server port but doesn't match any allowed routes. This feature uses the global responseControl system, but can be applied per server instance for strong isolation.

typescript
{
  "responseControl": {
    "enabled": true,
    "statusCode": 403,
    "content": { "error": "Access Denied to this Server Instance" },
    "contentType": "application/json",
    "headers": { "X-XMS-Status": "Filtered" }
  }
}

See the NotFound vs Response Control guide for a detailed comparison of visual 404 handlers vs functional response interception.

Security & Isolation

Independent Security

One port can have strict CSRF and Helmet, while another is open for public Webhooks.

Isolated XEMS

If enabled, each instance can have its own Encrypted Memory Store for session isolation.

Custom Logging

Logs are prefixed with the server id for easy debugging in multi-instance environments.

Programmatic Usage

typescript
import { createServer } from "xypriss";

const app = createServer({
  multiServer: {
    enabled: true,
    servers: [
      { id: "web", port: 3000 },
      { id: "api", port: 4000, routePrefix: "/api" }
    ]
  }
});

// Routes are distributed based on the XMS config
app.get("/", (req, res) => res.send("Web Home"));
app.get("/api/data", (req, res) => res.json({ data: [] }));

app.start();
Lifecycle Warning
When multiServer is enabled, app.start() will boot all configured instances concurrently. Ensure your system has permissions to bind to the requested ports before starting.
404 vs Response Control

Understand the difference between visual 404 templates and functional response interception.