Master Guides

Deployment

Two services, your choice of hosts.

A Master app is two deployable services — the Next.js frontend and the MasterController API. Run them on one box or split them; both are plain Node processes. The backend already ships with what operators expect: health endpoints, graceful shutdown, JSON logs in production, compression and env-var configuration.

Build & run together#

terminal
$ npm ci
$ master build # builds the Next.js frontend (the backend is plain ESM — no build)
$ NODE_ENV=production master start # backend: node server.js, frontend: next start

master start sets NODE_ENV=production for the backend and passes the ports from master.config.js. In production the backend loads config/appsettings.production.json (JSON logs, warn level) and config/environments/env.production.json, and turns the Swagger UI off (the /openapi.json document stays available).

Environment variables#

Production configuration comes from environment variables — the same Section:Key names your code reads, written as Section__Key. Never deploy the development secrets file.

backend environment
NODE_ENV=production
PORT=3001                                  # or Server__Port
FRONTEND_URL=https://example.com           # CORS origin (or Frontend__Url)
Auth__JwtSecret=<32+ random characters>    # enables JWT bearer auth (JWT_SECRET also works)
Auth__Issuer=my-app
Logging__LogLevel__Default=warn
frontend environment
NODE_ENV=production
PORT=3000
NEXT_PUBLIC_API_URL=https://api.example.com

Database credentials live in backend/config/environments/env.production.json, keyed by AppContext. Keep real passwords out of source — inject them at deploy time, or write that file from your secret store during the release. See Configuration and Secrets.

Migrations as a release step#

Apply pending migrations before the new version starts taking traffic — and review the SQL first if you like:

terminal
$ master db --env production script -o release.sql # optional: what will run
$ master db --env production migrate # apply (each migration is atomic)
$ master db --env production status # confirm

From inside backend/ without the CLI: NODE_ENV=production npx masterrecord update-database AppContext.

Health endpoints for load balancers#

server.js calls master.useHealthChecks() with a database check tagged ready, so every app exposes the ASP.NET-style trio:

EndpointUse it forBehaviour
GET /health/liveLiveness probe200 Healthy while the process runs; 503 once shutdown begins.
GET /health/readyReadiness probeRuns the ready-tagged checks (database canConnect()); 503 when a critical check fails or during graceful shutdown, so the balancer drains the instance.
GET /health/reportDashboards / humansEvery check with status, durationMs, data/error, plus uptimeSec.
GET /healthThe welcome pageA small { ok: true, ... } JSON ping from healthController.
GET /health/ready
{
  "status": "Healthy",
  "totalDurationMs": 3,
  "uptimeSec": 1842,
  "checks": {
    "database": { "status": "Healthy", "durationMs": 2 }
  }
}

Add more checks (Redis, an upstream API) with master.healthChecks.add(name, fn, { tags: ['ready'] }) — see Health Checks.

Graceful shutdown#

master.useGracefulShutdown() handles SIGTERM/SIGINT: readiness flips to 503, in-flight requests are drained, hosted services are stopped in order, and the process exits. Orchestrators that send SIGTERM and wait (Kubernetes, ECS, systemd, PM2) need no extra configuration — just make sure the stop timeout is longer than your slowest request.

Process manager (PM2)#

terminal
$ npm install -g pm2
$
$ cd backend && NODE_ENV=production PORT=3001 FRONTEND_URL=https://example.com Auth__JwtSecret=... pm2 start server.js --name app-api
$ cd frontend && PORT=3000 NEXT_PUBLIC_API_URL=https://api.example.com pm2 start "npm run start" --name app-web
$
$ pm2 save && pm2 startup

Useful: pm2 list, pm2 logs app-api, pm2 restart app-web, pm2 monit.

Reverse proxy#

text
https://example.com/       -> Next.js   (:3000)
https://api.example.com/   -> MasterController (:3001)   health: /health/live, /health/ready

Set NEXT_PUBLIC_API_URL=https://api.example.com and FRONTEND_URL=https://example.com accordingly. Responses are already gzip/brotli compressed by the backend.

Backend hardening#

MasterController ships production security features (HTTPS/HSTS, CSRF, rate limiting, secure headers). See the MasterController deployment guide to enable HTTPS in server.js and run through the production checklist.

Split deployments
Host the frontend on a platform like Vercel and the API on a Node host (Render, Fly, a VPS) — point NEXT_PUBLIC_API_URL at the API, set FRONTEND_URLto the frontend origin for CORS, and point the host’s health check at /health/ready.